From b96d37ab116702d45fb3b7bf82b455fa59ac36cb Mon Sep 17 00:00:00 2001 From: Ecio Date: Sat, 20 Jun 2026 17:19:05 -0300 Subject: [PATCH] feat: add pre-generated swagger.json; remove from .gitignore swagger-autogen is a devDep not present in the Docker image. Committing the generated file keeps the container self-contained. Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 1 - swagger.json | 269 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 swagger.json diff --git a/.gitignore b/.gitignore index da53f1a..5235962 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ node_modules/ .env data/ -swagger.json diff --git a/swagger.json b/swagger.json new file mode 100644 index 0000000..f26e4f9 --- /dev/null +++ b/swagger.json @@ -0,0 +1,269 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "WhatsApp Oficial API", + "description": "API REST para envio de mensagens via WhatsApp Cloud API (Meta). Suporta texto livre (janela 24h), templates aprovados e mídia.", + "version": "1.0.0" + }, + "components": { + "securitySchemes": { + "apiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key" + } + }, + "schemas": { + "ConfigureAccountRequest": { + "type": "object", + "required": ["phone_number_id", "access_token"], + "properties": { + "phone_number_id": { + "type": "string", + "example": "123456789012345", + "description": "ID do número no Meta for Developers" + }, + "access_token": { + "type": "string", + "example": "EAAxxxxx...", + "description": "Token de acesso permanente do app Meta" + }, + "waba_id": { + "type": "string", + "example": "987654321098765", + "description": "WhatsApp Business Account ID (necessário para listar templates)" + } + } + }, + "SendTextRequest": { + "type": "object", + "required": ["to", "type", "text"], + "properties": { + "to": { "type": "string", "example": "5511999998888" }, + "type": { "type": "string", "enum": ["text"], "example": "text" }, + "text": { "type": "string", "example": "Olá, tudo bem?" } + } + }, + "SendTemplateRequest": { + "type": "object", + "required": ["to", "type", "templateName"], + "properties": { + "to": { "type": "string", "example": "5511999998888" }, + "type": { "type": "string", "enum": ["template"], "example": "template" }, + "templateName": { "type": "string", "example": "hello_world" }, + "languageCode": { "type": "string", "example": "pt_BR", "default": "pt_BR" }, + "components": { + "type": "array", + "description": "Parâmetros do template (body/header). Omita se o template não tiver variáveis.", + "example": [{ "type": "body", "parameters": [{ "type": "text", "text": "João" }] }] + } + } + }, + "SendMediaRequest": { + "type": "object", + "required": ["to", "type", "mediaUrl"], + "properties": { + "to": { "type": "string", "example": "5511999998888" }, + "type": { "type": "string", "enum": ["image", "document", "audio", "video"], "example": "image" }, + "mediaUrl": { "type": "string", "example": "https://example.com/imagem.jpg" }, + "caption": { "type": "string", "example": "Confira nossa promoção!" } + } + }, + "SuccessResponse": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { "type": "string", "example": "Operação realizada com sucesso." } + } + }, + "ErrorResponse": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { "type": "string", "example": "Descrição do erro." } + } + }, + "AccountStatusResponse": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "accountId": { "type": "string", "example": "empresa1" }, + "state": { "type": "string", "enum": ["CONNECTED", "INVALID_TOKEN", "ERROR"], "example": "CONNECTED" }, + "displayPhoneNumber": { "type": "string", "example": "+55 11 99999-8888" }, + "verifiedName": { "type": "string", "example": "Empresa XPTO" }, + "qualityRating": { "type": "string", "example": "GREEN" } + } + } + } + }, + "security": [{ "apiKeyAuth": [] }], + "tags": [ + { "name": "Account", "description": "Configuração e verificação de credenciais WABA (phone_number_id, access_token)" }, + { "name": "Message", "description": "Envio de mensagens — texto livre (janela 24h), template aprovado ou mídia" }, + { "name": "Templates", "description": "Listagem de templates aprovados na conta WABA" } + ], + "paths": { + "/ping": { + "get": { + "tags": ["Account"], + "summary": "Health check simples", + "security": [], + "responses": { + "200": { "description": "pong" } + } + } + }, + "/account/configure/{accountId}": { + "post": { + "tags": ["Account"], + "summary": "Salvar / atualizar credenciais WABA de uma conta", + "parameters": [ + { "name": "accountId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "empresa1" } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ConfigureAccountRequest" } + } + } + }, + "responses": { + "200": { "description": "Credenciais salvas", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SuccessResponse" } } } }, + "400": { "description": "Campos obrigatórios ausentes" }, + "401": { "description": "API key inválida" } + } + } + }, + "/account/status/{accountId}": { + "get": { + "tags": ["Account"], + "summary": "Verificar status da conexão com a Meta", + "parameters": [ + { "name": "accountId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "empresa1" } + ], + "responses": { + "200": { "description": "CONNECTED", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountStatusResponse" } } } }, + "200a": { "description": "INVALID_TOKEN ou ERROR" }, + "401": { "description": "API key inválida" }, + "404": { "description": "Conta não encontrada" } + } + } + }, + "/account/remove/{accountId}": { + "delete": { + "tags": ["Account"], + "summary": "Remover credenciais de uma conta", + "parameters": [ + { "name": "accountId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "empresa1" } + ], + "responses": { + "200": { "description": "Conta removida", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SuccessResponse" } } } }, + "401": { "description": "API key inválida" }, + "404": { "description": "Conta não encontrada" } + } + } + }, + "/message/send/{accountId}": { + "post": { + "tags": ["Message"], + "summary": "Enviar mensagem (texto, template ou mídia)", + "parameters": [ + { "name": "accountId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "empresa1" } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { "$ref": "#/components/schemas/SendTextRequest" }, + { "$ref": "#/components/schemas/SendTemplateRequest" }, + { "$ref": "#/components/schemas/SendMediaRequest" } + ] + }, + "examples": { + "text": { "summary": "Texto livre (dentro da janela 24h)", "value": { "to": "5511999998888", "type": "text", "text": "Olá, tudo bem?" } }, + "template": { "summary": "Template aprovado", "value": { "to": "5511999998888", "type": "template", "templateName": "hello_world", "languageCode": "pt_BR" } }, + "template_params": { "summary": "Template com variável {{1}}", "value": { "to": "5511999998888", "type": "template", "templateName": "meu_template", "languageCode": "pt_BR", "components": [{ "type": "body", "parameters": [{ "type": "text", "text": "João" }] }] } }, + "image": { "summary": "Imagem com legenda", "value": { "to": "5511999998888", "type": "image", "mediaUrl": "https://example.com/img.jpg", "caption": "Confira!" } } + } + } + } + }, + "responses": { + "200": { "description": "Mensagem enviada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SuccessResponse" } } } }, + "400": { "description": "Parâmetros inválidos" }, + "401": { "description": "API key inválida" }, + "404": { "description": "Conta não encontrada" }, + "502": { "description": "Erro retornado pela Meta" } + } + } + }, + "/templates/{accountId}": { + "get": { + "tags": ["Templates"], + "summary": "Listar templates aprovados da conta WABA", + "description": "Requer waba_id configurado via /account/configure.", + "parameters": [ + { "name": "accountId", "in": "path", "required": true, "schema": { "type": "string" }, "example": "empresa1" } + ], + "responses": { + "200": { + "description": "Lista de templates", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean" }, + "templates": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "status": { "type": "string", "enum": ["APPROVED", "PENDING", "REJECTED"] }, + "category": { "type": "string" }, + "language": { "type": "string" } + } + } + } + } + } + } + } + }, + "400": { "description": "waba_id não configurado" }, + "401": { "description": "API key inválida" }, + "404": { "description": "Conta não encontrada" } + } + } + }, + "/webhooks/meta": { + "get": { + "tags": ["Account"], + "summary": "Verificação de webhook pelo Meta (hub.challenge)", + "security": [], + "parameters": [ + { "name": "hub.mode", "in": "query", "schema": { "type": "string" } }, + { "name": "hub.verify_token", "in": "query", "schema": { "type": "string" } }, + { "name": "hub.challenge", "in": "query", "schema": { "type": "string" } } + ], + "responses": { + "200": { "description": "Retorna hub.challenge se token válido" }, + "403": { "description": "Token inválido" } + } + }, + "post": { + "tags": ["Account"], + "summary": "Receber eventos do Meta e repassar ao whatsapp-sys", + "security": [], + "responses": { + "200": { "description": "Recebido (sempre responde 200 imediatamente)" } + } + } + } + } +}