{
  "openapi": "3.0.3",
  "info": {
    "title": "WhatsApp Secure API",
    "version": "1.0.0",
    "description": "API HTTPS con token Bearer nominativi, revocabili e con scadenza. Documentazione pubblica. Multi-account e account virtuale global. Invio testo, ricezione, revoca best effort. Vedere INTEGRAZIONE.html. Dispositivo collegato: il telefono resta principale. Lettura automatica attiva dopo il salvataggio; ogni applicazione gestisce separatamente il proprio cursore del feed. Per silenziare il telefono disabilitare le notifiche WhatsApp sul dispositivo."
  },
  "servers": [
    {
      "url": "/api/v1"
    },
    {
      "url": "https://wa.pepis.it/api/v1"
    }
  ],
  "security": [
    {
      "serviceToken": []
    }
  ],
  "paths": {
    "/accounts": {
      "get": {
        "summary": "Elenca account reali e global",
        "description": "Token con permesso read. ",
        "operationId": "getAccounts",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accounts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Account"
                      }
                    }
                  },
                  "required": [
                    "accounts"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      },
      "post": {
        "summary": "Crea account reale",
        "description": "Solo amministratore. ",
        "operationId": "postAccounts",
        "parameters": [
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://wa.pepis.it"
              ]
            },
            "description": ""
          }
        ],
        "responses": {
          "201": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "pattern": "^[a-z0-9][a-z0-9_-]{0,47}$"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  }
                },
                "required": [
                  "id",
                  "name"
                ]
              }
            }
          }
        },
        "security": [
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}": {
      "get": {
        "summary": "Stato account",
        "description": "Token con permesso read. ",
        "operationId": "getAccountsAccountid",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          }
        ],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/connect": {
      "post": {
        "summary": "Collega account reale",
        "description": "Solo amministratore. ",
        "operationId": "postAccountsAccountidConnect",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://wa.pepis.it"
              ]
            },
            "description": ""
          }
        ],
        "responses": {
          "202": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/disconnect": {
      "post": {
        "summary": "Scollega account reale, conserva storico",
        "description": "Solo amministratore. ",
        "operationId": "postAccountsAccountidDisconnect",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": ""
          },
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "https://wa.pepis.it"
              ]
            },
            "description": ""
          }
        ],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "state": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "state"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/qr": {
      "get": {
        "summary": "QR corrente per account reale",
        "description": "Solo amministratore. ",
        "operationId": "getAccountsAccountidQr",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          }
        ],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accountId": {
                      "type": "string"
                    },
                    "qr": {
                      "type": "string"
                    },
                    "dataUrl": {
                      "type": "string",
                      "description": "PNG data URL"
                    }
                  },
                  "required": [
                    "accountId",
                    "qr",
                    "dataUrl"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/messages": {
      "post": {
        "summary": "Invia testo o risposta, anche tramite global",
        "description": "Token con permesso send. 202 non garantisce consegna. Stessa chiave/contenuto/scope restituisce lo stesso tentativo. Non ritentare con chiave nuova se esito unknown. Global seleziona a rotazione gli account collegati, salvo accountId esplicito.",
        "operationId": "postAccountsAccountidMessages",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            },
            "description": ""
          }
        ],
        "responses": {
          "202": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResult"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "200": {
            "description": "Replay della richiesta; nessun nuovo invio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResult"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMessage"
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      },
      "get": {
        "summary": "Storico account o globale",
        "description": "Token con permesso read. ",
        "operationId": "getAccountsAccountidMessages",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "description": ""
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": ""
          },
          {
            "name": "chatId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": ""
          }
        ],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "messages": {
                      "type": "array",
                      "items": {
                        "allOf": [
                          {
                            "$ref": "#/components/schemas/Message"
                          },
                          {
                            "type": "object",
                            "properties": {
                              "accountId": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "accountId"
                            ]
                          }
                        ]
                      }
                    },
                    "nextOffset": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "messages",
                    "nextOffset"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/messages/{messageId}": {
      "get": {
        "summary": "Leggi singolo messaggio",
        "description": "Token con permesso read. ",
        "operationId": "getAccountsAccountidMessagesMessageid",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID opaco restituito dal servizio"
          },
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Obbligatorio quando il path usa global; account reale del messaggio"
          }
        ],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResult"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      },
      "delete": {
        "summary": "Richiedi eliminazione per tutti",
        "description": "Token con permesso revoke. Solo propri messaggi entro finestra locale (48h predefinite). Richiesta idempotente. requested non significa eliminazione confermata. Non elimina storico locale.",
        "operationId": "deleteAccountsAccountidMessagesMessageid",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID opaco restituito dal servizio"
          },
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Obbligatorio quando il path usa global; account reale del messaggio"
          }
        ],
        "responses": {
          "202": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResult"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/messages/{messageId}/media": {
      "get": {
        "summary": "Scarica allegato ricevuto",
        "description": "Token con permesso read. ",
        "operationId": "getAccountsAccountidMessagesMessageidMedia",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID opaco restituito dal servizio"
          },
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Obbligatorio quando il path usa global; account reale del messaggio"
          }
        ],
        "responses": {
          "200": {
            "description": "Media; Content-Disposition attachment",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/messages/{messageId}/revocation": {
      "get": {
        "summary": "Verifica possibilità locale di richiesta revoca",
        "description": "Token con permesso read. ",
        "operationId": "getAccountsAccountidMessagesMessageidRevocation",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID opaco restituito dal servizio"
          },
          {
            "name": "accountId",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Obbligatorio quando il path usa global; account reale del messaggio"
          }
        ],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accountId": {
                      "type": "string"
                    },
                    "canRequest": {
                      "type": "boolean"
                    },
                    "reason": {
                      "type": "string",
                      "nullable": true
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "policyHours": {
                      "type": "number"
                    },
                    "guaranteed": {
                      "type": "boolean",
                      "enum": [
                        false
                      ]
                    },
                    "revocation": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Revocation"
                        }
                      ],
                      "nullable": true
                    }
                  },
                  "required": [
                    "accountId",
                    "canRequest",
                    "guaranteed"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/events": {
      "get": {
        "summary": "Feed persistente account o globale",
        "description": "Token con permesso read. ",
        "operationId": "getAccountsAccountidEvents",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0,
              "default": 0
            },
            "description": ""
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            },
            "description": ""
          }
        ],
        "responses": {
          "200": {
            "description": "Successo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "nextCursor": {
                      "type": "integer",
                      "format": "int64"
                    },
                    "hasMore": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "events",
                    "nextCursor",
                    "hasMore"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      }
    },
    "/accounts/{accountId}/events/stream": {
      "get": {
        "summary": "Feed SSE con replay",
        "description": "Token con permesso read. ",
        "operationId": "getAccountsAccountidEventsStream",
        "parameters": [
          {
            "name": "accountId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID reale o global; global non ammesso per connect/disconnect/qr"
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int64",
              "minimum": 0,
              "default": 0
            },
            "description": ""
          },
          {
            "name": "Last-Event-ID",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Cursore persistito; prevale su after"
          }
        ],
        "responses": {
          "200": {
            "description": "SSE con id, event, data JSON Event. Heartbeat 15s. Riprendere con ultimo id elaborato.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Errore; vedere code e message",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Autenticazione non valida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Limite superato; rispettare Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "serviceToken": []
          },
          {
            "adminSession": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Message": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "whatsappId": {
            "type": "string"
          },
          "chatId": {
            "type": "string"
          },
          "participant": {
            "type": "string",
            "nullable": true
          },
          "senderPhone": {
            "type": "string",
            "nullable": true,
            "description": "Numero E.164 del mittente individuale, risolto esclusivamente dai metadati autenticati PN/LID del trasporto; null quando non risolvibile o nei gruppi."
          },
          "direction": {
            "type": "string",
            "enum": [
              "incoming",
              "outgoing"
            ]
          },
          "timestamp": {
            "type": "number",
            "description": "Unix secondi UTC"
          },
          "type": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "sending",
              "submitted",
              "unknown",
              "error",
              "server_ack",
              "delivered",
              "read",
              "played",
              "received"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "api",
              "live",
              "sync"
            ]
          },
          "media": {
            "type": "object",
            "nullable": true,
            "properties": {
              "mimeType": {
                "type": "string"
              },
              "fileName": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "receipts": {
            "type": "object",
            "additionalProperties": {
              "type": "object"
            },
            "description": "Ricevute per partecipante nei gruppi"
          },
          "revocation": {
            "$ref": "#/components/schemas/Revocation"
          },
          "whatsappRead": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "pending",
                  "retrying",
                  "submitted"
                ]
              },
              "attempts": {
                "type": "integer"
              },
              "nextAttemptAt": {
                "type": "number",
                "description": "Unix millisecondi"
              },
              "receiptSentAt": {
                "type": "string",
                "format": "date-time"
              },
              "submittedAt": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "status",
              "attempts"
            ]
          },
          "serviceId": {
            "type": "string",
            "nullable": true,
            "description": "Identificativo del token/servizio che ha iniziato l’invio"
          }
        },
        "required": [
          "id",
          "chatId",
          "direction",
          "timestamp",
          "text",
          "status"
        ]
      },
      "MessageResult": {
        "type": "object",
        "properties": {
          "accountId": {
            "type": "string"
          },
          "message": {
            "$ref": "#/components/schemas/Message"
          },
          "replayed": {
            "type": "boolean"
          }
        },
        "required": [
          "accountId",
          "message"
        ]
      },
      "Revocation": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "requesting",
              "requested",
              "observed",
              "unknown"
            ]
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time"
          },
          "observedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "status"
        ]
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "accountId": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "message.created",
              "message.updated",
              "account.updated"
            ]
          },
          "time": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Message"
              },
              {
                "type": "object",
                "properties": {
                  "state": {
                    "type": "string"
                  }
                },
                "required": [
                  "state"
                ]
              }
            ]
          }
        },
        "required": [
          "id",
          "accountId",
          "type",
          "time",
          "data"
        ]
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "state": {
            "type": "string"
          },
          "virtual": {
            "type": "boolean"
          },
          "enabled": {
            "type": "boolean"
          },
          "user": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "qrAvailable": {
            "type": "boolean"
          },
          "connectedAccounts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "id"
        ]
      },
      "SendMessage": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "description": "Numero internazionale o JID chat"
          },
          "text": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000
          },
          "accountId": {
            "type": "string",
            "description": "Mittente reale; facoltativo per global, obbligatorio con replyTo tramite global"
          },
          "replyTo": {
            "type": "string",
            "description": "ID opaco di un messaggio della stessa chat/account"
          }
        },
        "required": [
          "to",
          "text"
        ]
      }
    },
    "securitySchemes": {
      "serviceToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "wa_<256-bit random secret>",
        "description": "Permessi read/send/revoke, tutti gli account. Mai inviare il token nella query string."
      },
      "adminSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-wa_admin",
        "description": "Solo pannello amministrativo. Mutazioni richiedono Origin e X-CSRF-Token."
      }
    }
  }
}
