├── .env ├── .env.exemplo ├── .gitignore ├── API.md ├── Dockerfile ├── LICENSE ├── README.md ├── WuzAPI Collection.postman_collection.json ├── docker-compose-swarm.yaml ├── docker-compose.yml ├── frontend ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── index.html │ ├── manifest.json │ └── zpro.png ├── src │ ├── App.tsx │ ├── components │ │ ├── Footer.tsx │ │ ├── Navbar.tsx │ │ └── ProtectedRoute.tsx │ ├── contexts │ │ └── AuthContext.tsx │ ├── index.tsx │ └── pages │ │ ├── ApiDocs.tsx │ │ ├── Dashboard.tsx │ │ ├── Instances.tsx │ │ └── Login.tsx └── tsconfig.json ├── go.mod ├── go.sum ├── handlers.go ├── helpers.go ├── main.go ├── migrations ├── 0001_create_users_table.down.sql └── 0001_create_users_table.up.sql ├── repository └── repository.go ├── routes.go ├── static ├── api │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── index.html │ ├── spec.yml │ ├── swagger-ui-bundle.js │ ├── swagger-ui-bundle.js.map │ ├── swagger-ui-standalone-preset.js │ ├── swagger-ui-standalone-preset.js.map │ ├── swagger-ui.css │ ├── swagger-ui.css.map │ ├── swagger-ui.js │ └── swagger-ui.js.map ├── favicon.ico ├── github-markdown-css │ ├── code-navigation-banner-illo.svg │ └── github-css.css ├── images │ └── favicon.png ├── index.html ├── login │ └── index.html └── style.css ├── wmiau.go ├── wuzapi.exe └── wuzapi.service /.env: -------------------------------------------------------------------------------- 1 | # .env 2 | WUZAPI_ADMIN_TOKEN=1234ABCD 3 | DB_USER=zpro 4 | DB_PASSWORD=password 5 | DB_NAME=zpro 6 | DB_HOST=localhost 7 | DB_PORT=5432 8 | TZ=America/Sao_Paulo -------------------------------------------------------------------------------- /.env.exemplo: -------------------------------------------------------------------------------- 1 | # .env 2 | WUZAPI_ADMIN_TOKEN=1234ABCD 3 | DB_USER=postgres 4 | DB_PASSWORD=postgres 5 | DB_NAME=wuzapi 6 | DB_HOST=localhost 7 | DB_PORT=5432 8 | TZ=America/Sao_Paulo -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dbdata/ 2 | files/ 3 | wuzapi 4 | frontend/node_modules 5 | frontend/package-lock.json 6 | .env 7 | .env.example 8 | .tool-versions 9 | -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | # API Reference 2 | 3 | A API suporta dois tipos de autenticação: 4 | 5 | 1. **Token de usuário**: Para endpoints regulares, use o cabeçalho `Token` com o valor do token do usuário 6 | 2. **Token administrativo**: Para endpoints de administração (/admin/*), use o cabeçalho `Authorization` com o valor do token administrativo definido em WUZAPI_ADMIN_TOKEN 7 | 8 | Na primeira execução, o sistema cria automaticamente um usuário "admin" com o token definido na variável de ambiente WUZAPI_ADMIN_TOKEN. 9 | 10 | As chamadas à API devem ser feitas com o tipo de conteúdo JSON, com os parâmetros enviados no corpo da requisição, sempre passando o cabeçalho Token para autenticar a requisição. 11 | 12 | --- 13 | 14 | ## Admin 15 | 16 | Os seguintes endpoints de _admin_ são usados para gerenciar usuários no sistema. 17 | 18 | ## Listar usuários 19 | 20 | Lista todos os usuários cadastrados no sistema. 21 | 22 | Endpoint: _/admin/users_ 23 | 24 | Method: **GET** 25 | 26 | ``` 27 | curl -s -X GET -H 'Authorization: {{WUZAPI_ADMIN_TOKEN}}' http://localhost:8080/admin/users 28 | ``` 29 | 30 | Response: 31 | 32 | ```json 33 | [ 34 | { 35 | "id": 1, 36 | "name": "admin", 37 | "token": "H4Zbhwr72PBrtKdTIgS", 38 | "webhook": "https://example.com/webhook", 39 | "jid": "5491155553934@s.whatsapp.net", 40 | "qrcode": "", 41 | "connected": true, 42 | "expiration": 0, 43 | "events": "Message,ReadReceipt" 44 | } 45 | ] 46 | ``` 47 | 48 | ## Adicionar usuário 49 | 50 | Adiciona um novo usuário ao sistema. 51 | 52 | Endpoint: _/admin/users_ 53 | 54 | Method: **POST** 55 | 56 | ``` 57 | curl -s -X POST -H 'Authorization: {{WUZAPI_ADMIN_TOKEN}}' -H 'Content-Type: application/json' --data '{"name":"usuario2","token":"token2","webhook":"https://example.com/webhook2","events":"Message,ReadReceipt"}' http://localhost:8080/admin/users 58 | ``` 59 | 60 | Response: 61 | 62 | ```json 63 | { 64 | "id": 2 65 | } 66 | ``` 67 | 68 | ## Remover usuário 69 | 70 | Remove um usuário do sistema pelo seu ID. 71 | 72 | Endpoint: _/admin/users/{id}_ 73 | 74 | Method: **DELETE** 75 | 76 | ``` 77 | curl -s -X DELETE -H 'Authorization: {{WUZAPI_ADMIN_TOKEN}}' http://localhost:8080/admin/users/2 78 | ``` 79 | 80 | Response: 81 | 82 | ```json 83 | { 84 | "Details": "User deleted successfully" 85 | } 86 | ``` 87 | 88 | --- 89 | 90 | ## Webhook 91 | 92 | The following _webhook_ endpoints are used to get or set the webhook that will be called whenever a message or event is received. Available event types are: 93 | 94 | * Message 95 | * ReadReceipt 96 | * HistorySync 97 | * ChatPresence 98 | 99 | 100 | ## Sets webhook 101 | 102 | Configures the webhook to be called using POST whenever a subscribed event occurs. 103 | 104 | Endpoint: _/webhook_ 105 | 106 | Method: **POST** 107 | 108 | 109 | ``` 110 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"webhookURL":"https://some.server/webhook"}' http://localhost:8080/webhook 111 | ``` 112 | Response: 113 | 114 | ```json 115 | { 116 | "code": 200, 117 | "data": { 118 | "webhook": "https://example.net/webhook" 119 | }, 120 | "success": true 121 | } 122 | ``` 123 | 124 | --- 125 | 126 | ## Gets webhook 127 | 128 | Retrieves the configured webhook and subscribed events. 129 | 130 | Endpoint: _/webhook_ 131 | 132 | Method: **GET** 133 | 134 | ``` 135 | curl -s -X GET -H 'Token: 1234ABCD' http://localhost:8080/webhook 136 | ``` 137 | Response: 138 | ```json 139 | { 140 | "code": 200, 141 | "data": { 142 | "subscribe": [ "Message" ], 143 | "webhook": "https://example.net/webhook" 144 | }, 145 | "success": true 146 | } 147 | ``` 148 | 149 | --- 150 | 151 | ## Session 152 | 153 | The following _session_ endpoints are used to start a session to Whatsapp servers in order to send and receive messages 154 | 155 | ## Connect 156 | 157 | Connects to Whatsapp servers. If is there no existing session it will initiate a QR scan that can be retrieved via the [/session/qr](#user-content-gets-qr-code) endpoint. 158 | You can subscribe to different types of messages so they are POSTED to your configured webhook. 159 | Available message types to subscribe to are: 160 | 161 | * Message 162 | * ReadReceipt 163 | * HistorySync 164 | * ChatPresence 165 | 166 | If you set Immediate to false, the action will wait 10 seconds to verify a successful login. If Immediate is not set or set to true, it will return immedialty, but you will have to check shortly after the /session/status as your session might be disconnected shortly after started if the session was terminated previously via the phone/device. 167 | 168 | Endpoint: _/session/connect_ 169 | 170 | Method: **POST** 171 | 172 | ``` 173 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Subscribe":["Message"],"Immediate":false}' http://localhost:8080/session/connect 174 | ``` 175 | 176 | Response: 177 | 178 | ```json 179 | { 180 | "code": 200, 181 | "data": { 182 | "details": "Connected!", 183 | "events": "Message", 184 | "jid": "5491155554444.0:52@s.whatsapp.net", 185 | "webhook": "http://some.site/webhook?token=123456" 186 | }, 187 | "success": true 188 | } 189 | ``` 190 | 191 | --- 192 | 193 | ## Disconnect 194 | 195 | Disconnects from Whatsapp servers, keeping the session active. This means that if you /session/connect again, it will 196 | reuse the session and won't require a QR code rescan. 197 | 198 | Endpoint: _/session/disconnect_ 199 | 200 | Method: **POST** 201 | 202 | 203 | ``` 204 | curl -s -X POST -H 'Token: 1234ABCD' http://localhost:8080/session/disconnect 205 | ``` 206 | 207 | Response: 208 | 209 | ```json 210 | { 211 | "code": 200, 212 | "data": { 213 | "Details": "Disconnected" 214 | }, 215 | "success": true 216 | } 217 | ``` 218 | 219 | --- 220 | 221 | ## Logout 222 | 223 | Disconnects from whatsapp websocket *and* finishes the session (so it will be required to scan a QR code the next time a connection is initiated) 224 | 225 | Endpoint: _/session/logout_ 226 | 227 | Method: **POST** 228 | 229 | ``` 230 | curl -s -X POST -H 'Token: 1234ABCD' http://localhost:8080/session/logout 231 | ``` 232 | 233 | Response: 234 | 235 | ```json 236 | { 237 | "code": 200, 238 | "data": { 239 | "Details": "Logged out" 240 | }, 241 | "success": true 242 | } 243 | 244 | ``` 245 | 246 | --- 247 | 248 | ## Status 249 | 250 | Retrieve status (IsConnected means websocket connection is initiated, IsLoggedIn means QR code was scanned and session is ready to receive/send messages) 251 | 252 | If its not logged in, you can use the [/session/qr](#user-content-gets-qr-code) endpoint to get the QR code to scan 253 | 254 | Endpoint: _/session/status_ 255 | 256 | Method: **GET** 257 | 258 | ``` 259 | curl -s -H 'Token: 1234ABCD' http://localhost:8080/session/status 260 | ``` 261 | 262 | Response: 263 | 264 | ```json 265 | { 266 | "code": 200, 267 | "data": { 268 | "Connected": true, 269 | "LoggedIn": true 270 | }, 271 | "success": true 272 | } 273 | 274 | ``` 275 | 276 | --- 277 | 278 | ## Gets QR code 279 | 280 | Retrieves QR code, session must be connected to Whatsapp servers and logged in must be false in order for the QR code to be generated. The generated code 281 | will be returned encoded in base64 embedded format. 282 | 283 | Endpoint: _/session/qr_ 284 | 285 | Method: **GET** 286 | 287 | ``` 288 | curl -s -H 'Token: 1234ABCD' http://localhost:8080/session/qr 289 | ``` 290 | Response: 291 | ```json 292 | { 293 | "code": 200, 294 | "data": { 295 | "QRCode": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAABlBMVEX///8AAABVwtN+AAAEw0lEQVR42uyZ..." 296 | }, 297 | "success": true 298 | } 299 | ``` 300 | 301 | --- 302 | 303 | ## User 304 | 305 | The following _user_ endpoints are used to gather information about Whatsapp users. 306 | 307 | ## Gets user details 308 | 309 | Gets information for users on Whatsapp 310 | 311 | Endpoint: _/user/info_ 312 | 313 | Method: **POST** 314 | 315 | ``` 316 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":["5491155554445","5491155554444"]}' http://localhost:8080/user/info 317 | ``` 318 | 319 | Response: 320 | 321 | ```json 322 | { 323 | "code": 200, 324 | "data": { 325 | "Users": { 326 | "5491155554445@s.whatsapp.net": { 327 | "Devices": [], 328 | "PictureID": "", 329 | "Status": "", 330 | "VerifiedName": null 331 | }, 332 | "5491155554444@s.whatsapp.net": { 333 | "Devices": [ 334 | "5491155554444.0:0@s.whatsapp.net", 335 | "5491155554444.0:11@s.whatsapp.net" 336 | ], 337 | "PictureID": "", 338 | "Status": "", 339 | "VerifiedName": { 340 | "Certificate": { 341 | "details": "CP7t782FIRIGc21iOndeshIghUcml4b2NvbQ==", 342 | "signature": "e35Fd320dccNmaBdNw+Yqtz1Q5545XpT9PpSlntqwaXpj1boOrQUnq9TNhYzGtgPWznTjRl7kHEBQ==" 343 | }, 344 | "Details": { 345 | "issuer": "smb:wa", 346 | "serial": 23810327841439764000, 347 | "verifiedName": "Great Company" 348 | } 349 | } 350 | } 351 | } 352 | }, 353 | "success": true 354 | } 355 | ``` 356 | 357 | --- 358 | 359 | ## Checks Users 360 | 361 | Checks if phone numbers are registered as Whatsapp users 362 | 363 | Endpoint: _/user/check_ 364 | 365 | Method: **POST** 366 | 367 | ``` 368 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":["5491155554445","5491155554444"]}' http://localhost:8080/user/check 369 | ``` 370 | 371 | Response: 372 | 373 | ```json 374 | { 375 | "code": 200, 376 | "data": { 377 | "Users": [ 378 | { 379 | "IsInWhatsapp": true, 380 | "JID": "5491155554445@s.whatsapp.net", 381 | "Query": "5491155554445", 382 | "VerifiedName": "Company Name" 383 | }, 384 | { 385 | "IsInWhatsapp": false, 386 | "JID": "5491155554444@s.whatsapp.net", 387 | "Query": "5491155554444", 388 | "VerifiedName": "" 389 | } 390 | ] 391 | }, 392 | "success": true 393 | } 394 | ``` 395 | 396 | --- 397 | 398 | ## Gets Avatar 399 | 400 | Gets information about users profile pictures on WhatsApp, either a thumbnail (Preview=true) or full picture. 401 | 402 | Endpoint: _/user/avatar_ 403 | 404 | Method: **GET** 405 | 406 | ``` 407 | curl -s -X GET -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554445","Preview":true]}' http://localhost:8080/user/avatar 408 | ``` 409 | 410 | Response: 411 | 412 | ```json 413 | { 414 | "URL": "https://pps.whatsapp.net/v/t61.24694-24/227295214_112447507729487_4643695328050510566_n.jpg?stp=dst-jpg_s96x96&ccb=11-4&oh=ja432434a91e8f41d86d341bx889c217&oe=543222A4", 415 | "ID": "1645308319", 416 | "Type": "preview", 417 | "DirectPath": "/v/t61.24694-24/227295214_112447507729487_4643695328050510566_n.jpg?stp=dst-jpg_s96x96&ccb=11-4&oh=ja432434a91e8f41d86d341ba889c217&oe=543222A4" 418 | } 419 | ``` 420 | 421 | --- 422 | 423 | ## Gets all contacts 424 | 425 | Gets all contacts for the account. 426 | 427 | Endpoint: _/user/contacts_ 428 | 429 | Method: **GET** 430 | 431 | ``` 432 | curl -s -X GET -H 'Token: 1234ABCD' http://localhost:8080/user/contacts 433 | ``` 434 | 435 | Response: 436 | 437 | ```json 438 | { 439 | "code": 200, 440 | "data": { 441 | "5491122223333@s.whatsapp.net": { 442 | "BusinessName": "", 443 | "FirstName": "", 444 | "Found": true, 445 | "FullName": "", 446 | "PushName": "FOP2" 447 | }, 448 | "549113334444@s.whatsapp.net": { 449 | "BusinessName": "", 450 | "FirstName": "", 451 | "Found": true, 452 | "FullName": "", 453 | "PushName": "Asternic" 454 | } 455 | } 456 | } 457 | ``` 458 | 459 | --- 460 | 461 | 462 | # Chat 463 | 464 | The following _chat_ endpoints are used to send messages or mark them as read or indicating composing/not composing presence. The sample response is listed only once, as it is the 465 | same for all message types. 466 | 467 | ## Send Text Message 468 | 469 | Sends a text message or reply. For replies, ContextInfo data should be completed with the StanzaID (ID of the message we are replying to), and Participant (user JID we are replying to). If ID is 470 | ommited, a random message ID will be generated. 471 | 472 | Endpoint: _/chat/send/text_ 473 | 474 | Method: **POST** 475 | 476 | Example sending a new message: 477 | 478 | ``` 479 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Body":"Hellow Meow", "Id": "90B2F8B13FAC8A9CF6B06E99C7834DC5"}' http://localhost:8080/chat/send/text 480 | ``` 481 | Example replying to some message: 482 | 483 | ``` 484 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Body":"Ditto","ContextInfo":{"StanzaId":"AA3DSE28UDJES3","Participant":"5491155553935@s.whatsapp.net"}}' http://localhost:8080/chat/send/text 485 | ``` 486 | 487 | Response: 488 | 489 | ```json 490 | { 491 | "code": 200, 492 | "data": { 493 | "Details": "Sent", 494 | "Id": "90B2F8B13FAC8A9CF6B06E99C7834DC5", 495 | "Timestamp": "2022-04-20T12:49:08-03:00" 496 | }, 497 | "success": true 498 | } 499 | ``` 500 | 501 | --- 502 | 503 | ## Send Template Message 504 | 505 | Sends a template message or reply. Template messages can contain call to action buttons: up to three quick replies, call button, and link button. 506 | 507 | Endpoint: _/chat/send/template_ 508 | 509 | Method: **POST** 510 | 511 | 512 | ``` 513 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Content":"Template content","Footer":"Some footer text","Buttons":[{"DisplayText":"Yes","Type":"quickreply"},{"DisplayText":"No","Type":"quickreply"},{"DisplayText":"Visit Site","Type":"url","Url":"https://www.fop2.com"},{"DisplayText":"Llamame","Type":"call","PhoneNumber":"1155554444"}]}' http://localhost:8080/chat/send/template 514 | ``` 515 | 516 | --- 517 | 518 | ## Send Audio Message 519 | 520 | Sends an Audio message. Audio must be in Opus format and base64 encoded in embedded format. 521 | 522 | Endpoint: _/chat/send/audio_ 523 | 524 | Method: **POST** 525 | 526 | 527 | ``` 528 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Audio":"data:audio/ogg;base64,T2dnUw..."}' http://localhost:8080/chat/send/audio 529 | ``` 530 | 531 | ## Send Image Message 532 | 533 | Sends an Image message. Image must be in png or jpeg and base64 encoded in embedded format. You can optionally specify a text Caption 534 | 535 | Endpoint: _/chat/send/image_ 536 | 537 | Method: **POST** 538 | 539 | 540 | ``` 541 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Caption":"Look at this", "Image":"data:image/jpeg;base64,iVBORw0KGgoAAAANSU..."}' http://localhost:8080/chat/send/image 542 | ``` 543 | 544 | --- 545 | 546 | ## Send Document Message 547 | 548 | Sends a Document message. Any mime type can be attached. A FileName must be supplied in the request body. The Document must be passed as octet-stream in base64 embedded format. 549 | 550 | Endpoint: _/chat/send/document_ 551 | 552 | Method: **POST** 553 | 554 | 555 | ``` 556 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","FileName":"hola.txt","Document":"data:application/octet-stream;base64,aG9sYSBxdWUgdGFsCg=="}' http://localhost:8080/chat/send/document 557 | ``` 558 | 559 | --- 560 | 561 | ## Send Video Message 562 | 563 | Sends a Video message. Video must be in mp4 or 3gpp and base64 encoded in embedded format. You can optionally specify a text Caption and a JpegThumbnail 564 | 565 | Endpoint: _/chat/send/video_ 566 | 567 | Method: **POST** 568 | 569 | 570 | ``` 571 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Caption":"Look at this", "Video":"data:image/jpeg;base64,iVBORw0KGgoAAAANSU..."}' http://localhost:8080/chat/send/video 572 | ``` 573 | 574 | 575 | --- 576 | 577 | ## Send Sticker Message 578 | 579 | Sends a Sticker message. Sticker must be in image/webp format and base64 encoded in embedded format. You can optionally specify a PngThumbnail 580 | 581 | Endpoint: _/chat/send/sticker_ 582 | 583 | Method: **POST** 584 | 585 | 586 | ``` 587 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","PngThumbnail":"VBORgoAANSU=", "Sticker":"data:image/jpeg;base64,iVBORw0KGgoAAAANSU..."}' http://localhost:8080/chat/send/sticker 588 | ``` 589 | 590 | 591 | --- 592 | 593 | ## Send Location Message 594 | 595 | Sends a Location message. Latitude and Longitude must be passed, with an optional Name 596 | 597 | Endpoint: _/chat/send/location_ 598 | 599 | Method: **POST** 600 | 601 | 602 | ``` 603 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Latitude":48.858370,"Longitude":2.294481,"Phone":"5491155554444","Name":"Paris"}' http://localhost:8080/chat/send/location 604 | ``` 605 | 606 | --- 607 | 608 | ## Send Contact Message 609 | 610 | Sends a Contact message. Both Vcard and Name body parameters are mandatory. 611 | 612 | Endpoint: _/chat/send/contact_ 613 | 614 | Method: **POST** 615 | 616 | 617 | ``` 618 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Name":"Casa","Vcard":"BEGIN:VCARD\nVERSION:3.0\nN:Doe;John;;;\nFN:John Doe\nORG:Example.com Inc.;\nTITLE:Imaginary test person\nEMAIL;type=INTERNET;type=WORK;type=pref:johnDoe@example.org\nTEL;type=WORK;type=pref:+1 617 555 1212\nTEL;type=WORK:+1 (617) 555-1234\nTEL;type=CELL:+1 781 555 1212\nTEL;type=HOME:+1 202 555 1212\nitem1.ADR;type=WORK:;;2 Enterprise Avenue;Worktown;NY;01111;USA\nitem1.X-ABADR:us\nitem2.ADR;type=HOME;type=pref:;;3 Acacia Avenue;Hoitem2.X-ABADR:us\nEND:VCARD"}' http://localhost:8080/chat/send/contact 619 | ``` 620 | 621 | --- 622 | 623 | ## Chat Presence Indication 624 | 625 | Sends indication if you are writing/composing a text or audio message to the other party. possible states are "composing" and "paused". if media is set to "audio" it will indicate an audio message is being recorded. 626 | 627 | endpoint: _/chat/presence_ 628 | 629 | method: **POST** 630 | 631 | ``` 632 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","State":"composing","Media":""}' http://localhost:8080/chat/presence 633 | ``` 634 | 635 | --- 636 | 637 | ## Mark message(s) as read 638 | 639 | Indicates that one or more messages were read. Id is an array of messages Ids. 640 | Chat must always be set to the chat ID (user ID in DMs and group ID in group chats). 641 | Sender must be set in group chats and must be the user ID who sent the message. 642 | 643 | endpoint: _/chat/markread_ 644 | 645 | method: **POST** 646 | 647 | ``` 648 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Id":["AABBCCDD112233","IIOOPPLL43332"]","Chat":"5491155553934.0:1@s.whatsapp.net"}' http://localhost:8080/chat/markread 649 | ``` 650 | 651 | --- 652 | 653 | ## React to messages 654 | 655 | Sends a reaction for an existing message. Id is the message Id to react to, if its your own message, prefix the Id with the string 'me:' 656 | 657 | endpoint: _/chat/react_ 658 | 659 | method: **POST** 660 | 661 | ``` 662 | curl -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Phone":"5491155554444","Body":"❤️","Id":"me:069EDE53E81CB5A4773587FB96CB3ED3"}' http://localhost:8080/chat/react 663 | ``` 664 | 665 | --- 666 | 667 | ## Download Image 668 | 669 | Downloads an Image from a message and retrieves it Base64 media encoded. Required request parameters are: Url, MediaKey, Mimetype, FileSHA256 and FileLength 670 | 671 | endpoint: _/chat/downloadimage_ 672 | 673 | method: **POST** 674 | 675 | ``` 676 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Url":"https://mmg.whatsapp.net/d/f/Apah954sUug5I9GnQsmXKPUdUn3ZPKGYFnscJU02dpuD.enc","Mimetype":"image/jpeg", "FileSHA256":"nMthnfkUWQiMfNJpA6K9+ft+Dx9Mb1STs+9wMHjeo/M=","FileLength":2039,"MediaKey":"vq0RR0nYGkxm2HrpwUp3sK8A7Nr1KUcOiBHrT1hg+PU=","FileEncSHA256":"6bMVZ5dRf9JKxJSUgg4w1h3iSYA3dM8gEQxaMPwoONc="}' http://localhost:8080/chat/downloadimage 677 | ``` 678 | 679 | --- 680 | 681 | ## Download Video 682 | 683 | Downloads a Video from a message and retrieves it Base64 media encoded. Required request parameters are: Url, MediaKey, Mimetype, FileSHA256 and FileLength 684 | 685 | endpoint: _/chat/downloadvideo_ 686 | 687 | method: **POST** 688 | 689 | ``` 690 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Url":"https://mmg.whatsapp.net/d/f/Apah954sUug5I9GnQsmXKPUdUn3ZPKGYFnscJU02dpuD.enc","Mimetype":"video/mp4", "FileSHA256":"nMthnfkUWQiMfNJpA6K9+ft+Dx9Mb1STs+9wMHjeo/M=","FileLength":2039,"MediaKey":"vq0RR0nYGkxm2HrpwUp3sK8A7Nr1KUcOiBHrT1hg+PU=","FileEncSHA256":"6bMVZ5dRf9JKxJSUgg4w1h3iSYA3dM8gEQxaMPwoONc="}' http://localhost:8080/chat/downloadvideo 691 | ``` 692 | 693 | --- 694 | 695 | ## Download Audio 696 | 697 | Downloads an Audio from a message and retrieves it Base64 media encoded. Required request parameters are: Url, MediaKey, Mimetype, FileSHA256 and FileLength 698 | 699 | endpoint: _/chat/downloadaudio_ 700 | 701 | method: **POST** 702 | 703 | ``` 704 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Url":"https://mmg.whatsapp.net/d/f/Apah954sUug5I9GnQsmXKPUdUn3ZPKGYFnscJU02dpuD.enc","Mimetype":"audio/ogg; codecs=opus", "FileSHA256":"nMthnfkUWQiMfNJpA6K9+ft+Dx9Mb1STs+9wMHjeo/M=","FileLength":2039,"MediaKey":"vq0RR0nYGkxm2HrpwUp3sK8A7Nr1KUcOiBHrT1hg+PU=","FileEncSHA256":"6bMVZ5dRf9JKxJSUgg4w1h3iSYA3dM8gEQxaMPwoONc="}' http://localhost:8080/chat/downloadaudio 705 | ``` 706 | 707 | --- 708 | 709 | ## Download Document 710 | 711 | Downloads a Document from a message and retrieves it Base64 media encoded. Required request parameters are: Url, MediaKey, Mimetype, FileSHA256 and FileLength 712 | 713 | endpoint: _/chat/downloaddocument_ 714 | 715 | method: **POST** 716 | 717 | ``` 718 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"Url":"https://mmg.whatsapp.net/d/f/Apah954sUug5I9GnQsmXKPUdUn3ZPKGYFnscJU02dpuD.enc","Mimetype":"application/pdf", "FileSHA256":"nMthnfkUWQiMfNJpA6K9+ft+Dx9Mb1STs+9wMHjeo/M=","FileLength":2039,"MediaKey":"vq0RR0nYGkxm2HrpwUp3sK8A7Nr1KUcOiBHrT1hg+PU=","FileEncSHA256":"6bMVZ5dRf9JKxJSUgg4w1h3iSYA3dM8gEQxaMPwoONc="}' http://localhost:8080/chat/downloaddocument 719 | ``` 720 | 721 | --- 722 | 723 | ## Group 724 | 725 | The following _group_ endpoints are used to gather information or perfrom actions in chat groups. 726 | 727 | ## List subscribed groups 728 | 729 | Returns complete list of subscribed groups 730 | 731 | endpoint: _/group/list_ 732 | 733 | method: **GET** 734 | 735 | 736 | ``` 737 | curl -s -X GET -H 'Token: 1234ABCD' http://localhost:8080/group/list 738 | ```` 739 | 740 | Response: 741 | ```json 742 | { 743 | "code": 200, 744 | "data": { 745 | "Groups": [ 746 | { 747 | "AnnounceVersionID": "1650572126123738", 748 | "DisappearingTimer": 0, 749 | "GroupCreated": "2022-04-21T17:15:26-03:00", 750 | "IsAnnounce": false, 751 | "IsEphemeral": false, 752 | "IsLocked": false, 753 | "JID": "120362023605733675@g.us", 754 | "Name": "Super Group", 755 | "NameSetAt": "2022-04-21T17:15:26-03:00", 756 | "NameSetBy": "5491155554444@s.whatsapp.net", 757 | "OwnerJID": "5491155554444@s.whatsapp.net", 758 | "ParticipantVersionID": "1650234126145738", 759 | "Participants": [ 760 | { 761 | "IsAdmin": true, 762 | "IsSuperAdmin": true, 763 | "JID": "5491155554444@s.whatsapp.net" 764 | }, 765 | { 766 | "IsAdmin": false, 767 | "IsSuperAdmin": false, 768 | "JID": "5491155553333@s.whatsapp.net" 769 | }, 770 | { 771 | "IsAdmin": false, 772 | "IsSuperAdmin": false, 773 | "JID": "5491155552222@s.whatsapp.net" 774 | } 775 | ], 776 | "Topic": "", 777 | "TopicID": "", 778 | "TopicSetAt": "0001-01-01T00:00:00Z", 779 | "TopicSetBy": "" 780 | } 781 | ] 782 | }, 783 | "success": true 784 | } 785 | ``` 786 | 787 | --- 788 | 789 | ## Get group invite link 790 | 791 | Gets the invite link for a group 792 | 793 | endpoint: _/group/invitelink_ 794 | 795 | method: **GET** 796 | 797 | 798 | ``` 799 | curl -s -X GET -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"GroupJID":"120362023605733675@g.us"}' http://localhost:8080/group/invitelink 800 | ``` 801 | 802 | Response: 803 | 804 | ```json 805 | { 806 | "code": 200, 807 | "data": { 808 | "InviteLink": "https://chat.whatsapp.com/HffXhYmzzyJGec61oqMXiz" 809 | }, 810 | "success": true 811 | } 812 | ``` 813 | 814 | --- 815 | 816 | ## Gets group information 817 | 818 | Retrieves information about a specific group 819 | 820 | endpoint: _/group/info_ 821 | 822 | method: **GET** 823 | 824 | 825 | ``` 826 | curl -s -X GET -H 'Token: 1234ABCD' -H 'Content-Type: application/json' --data '{"GroupJID":"120362023605733675@g.us"}' http://localhost:8080/group/info 827 | ``` 828 | 829 | Response: 830 | 831 | ```json 832 | { 833 | "code": 200, 834 | "data": { 835 | "AnnounceVersionID": "1650572126123738", 836 | "DisappearingTimer": 0, 837 | "GroupCreated": "2022-04-21T17:15:26-03:00", 838 | "IsAnnounce": false, 839 | "IsEphemeral": false, 840 | "IsLocked": false, 841 | "JID": "120362023605733675@g.us", 842 | "Name": "Super Group", 843 | "NameSetAt": "2022-04-21T17:15:26-03:00", 844 | "NameSetBy": "5491155554444@s.whatsapp.net", 845 | "OwnerJID": "5491155554444@s.whatsapp.net", 846 | "ParticipantVersionID": "1650234126145738", 847 | "Participants": [ 848 | { 849 | "IsAdmin": true, 850 | "IsSuperAdmin": true, 851 | "JID": "5491155554444@s.whatsapp.net" 852 | }, 853 | { 854 | "IsAdmin": false, 855 | "IsSuperAdmin": false, 856 | "JID": "5491155553333@s.whatsapp.net" 857 | }, 858 | { 859 | "IsAdmin": false, 860 | "IsSuperAdmin": false, 861 | "JID": "5491155552222@s.whatsapp.net" 862 | } 863 | ], 864 | "Topic": "", 865 | "TopicID": "", 866 | "TopicSetAt": "0001-01-01T00:00:00Z", 867 | "TopicSetBy": "" 868 | }, 869 | "success": true 870 | } 871 | ``` 872 | 873 | --- 874 | 875 | ## Changes group photo 876 | 877 | Allows you to change a group photo/image 878 | 879 | endpoint: _/group/photo_ 880 | 881 | method: **POST** 882 | 883 | 884 | ``` 885 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' -d '{"GroupJID":"120362023605733675@g.us","Image":"data:image/jpeg;base64,AABB00DD-"}' http://localhost:8080/group/photo 886 | ``` 887 | 888 | Response: 889 | 890 | ```json 891 | { 892 | "code": 200, 893 | "data": { 894 | "Details": "Group Photo set successfully", 895 | "PictureID": "122233212312" 896 | }, 897 | "success": true 898 | } 899 | ``` 900 | 901 | 902 | --- 903 | 904 | ## Changes group name 905 | 906 | Allows you to change a group name 907 | 908 | endpoint: _/group/name_ 909 | 910 | method: **POST** 911 | 912 | 913 | 914 | ``` 915 | curl -s -X POST -H 'Token: 1234ABCD' -H 'Content-Type: application/json' -d '{"GroupJID":"120362023605733675@g.us","Name":"New Group Name"}' http://localhost:8080/group/name 916 | ``` 917 | 918 | Response: 919 | 920 | ```json 921 | { 922 | "code": 200, 923 | "data": { 924 | "Details": "Group Name set successfully" 925 | }, 926 | "success": true 927 | } 928 | ``` 929 | 930 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.23-alpine3.20 AS builder 2 | 3 | RUN apk update && apk add --no-cache gcc musl-dev gcompat 4 | 5 | WORKDIR /app 6 | COPY go.mod go.sum ./ 7 | RUN go mod download 8 | 9 | COPY . . 10 | ENV CGO_ENABLED=1 11 | RUN go build -o wuzapi 12 | 13 | FROM alpine:3.20 14 | 15 | RUN apk update && apk add --no-cache \ 16 | ca-certificates \ 17 | netcat-openbsd \ 18 | postgresql-client \ 19 | openssl \ 20 | curl \ 21 | ffmpeg \ 22 | tzdata 23 | 24 | ENV TZ="America/Sao_Paulo" 25 | WORKDIR /app 26 | 27 | COPY --from=builder /app/wuzapi /app/ 28 | COPY --from=builder /app/static /app/static/ 29 | COPY --from=builder /app/migrations /app/migrations/ 30 | COPY --from=builder /app/files /app/files/ 31 | COPY --from=builder /app/repository /app/repository/ 32 | COPY --from=builder /app/dbdata /app/dbdata/ 33 | COPY --from=builder /app/wuzapi.service /app/wuzapi.service 34 | 35 | RUN chmod +x /app/wuzapi 36 | RUN chmod -R 755 /app 37 | RUN chown -R root:root /app 38 | 39 | VOLUME [ "/app/dbdata", "/app/files" ] 40 | 41 | ENTRYPOINT ["/app/wuzapi", "--logtype=console", "--color=true"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Nicolas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WuzAPI 2 | 3 | WuzAPI is an implementation 4 | of [@tulir/whatsmeow](https://github.com/tulir/whatsmeow) library as a 5 | simple RESTful API service with multiple device support and concurrent 6 | sessions. 7 | 8 | Whatsmeow does not use Puppeteer on headless Chrome, nor an Android emulator. 9 | It talks directly to WhatsApp websocket servers, thus is quite fast and uses 10 | much less memory and CPU than those solutions. The drawback is that a change 11 | in the WhatsApp protocol could break connections and will require a library 12 | update. 13 | 14 | ## :warning: Warning 15 | 16 | **Using this software violating WhatsApp ToS can get your number banned**: 17 | Be very careful, do not use this to send SPAM or anything like it. Use at 18 | your own risk. If you need to develop something with commercial interest 19 | you should contact a WhatsApp global solution provider and sign up for the 20 | Whatsapp Business API service instead. 21 | 22 | ## Available endpoints 23 | 24 | * Session: connect, disconnect and logout from WhatsApp. Retrieve 25 | connection status. Retrieve QR code for scanning. 26 | * Messages: send text, image, audio, document, template, video, sticker, 27 | location and contact messages. 28 | * Users: check if phones have whatsapp, get user information, get user avatar, 29 | retrieve full contact list. 30 | * Chat: set presence (typing/paused,recording media), mark messages as read, 31 | download images from messages, send reactions. 32 | * Groups: list subscribed, get info, get invite links, change photo and name. 33 | * Webhooks: set and get webhook that will be called whenever events/messages 34 | are received. 35 | 36 | ## Prerequisites 37 | 38 | Packages: 39 | 40 | * Go (Go Programming Language) 41 | 42 | Optional: 43 | 44 | * Docker (Containerization) 45 | 46 | ## Atualização de dependências 47 | 48 | Este projeto utiliza a biblioteca whatsmeow para comunicação com o WhatsApp. Para atualizar a biblioteca para a versão mais recente, execute: 49 | 50 | ```bash 51 | go get -u go.mau.fi/whatsmeow@latest 52 | go mod tidy 53 | ``` 54 | 55 | ## Building 56 | 57 | ``` 58 | go build . 59 | ``` 60 | 61 | ## Run 62 | 63 | By default it will start a REST service in port 8080. These are the parameters 64 | you can use to alter behaviour 65 | 66 | * -address : sets the IP address to bind the server to (default 0.0.0.0) 67 | * -port : sets the port number (default 8080) 68 | * -logtype : format for logs, either console (default) or json 69 | * -wadebug : enable whatsmeow debug, either INFO or DEBUG levels are suported 70 | * -sslcertificate : SSL Certificate File 71 | * -sslprivatekey : SSL Private Key File 72 | * -admintoken : your admin token to create, get, or delete users from database 73 | * --logtype=console --color=true 74 | * --logtype json 75 | 76 | Example: 77 | 78 | Para ter logs coloridos: 79 | ``` 80 | Depois: 81 | ``` 82 | ./wuzapi --logtype=console --color=true 83 | ``` 84 | (ou -color no Docker, etc.) 85 | 86 | Para logs em JSON: 87 | Rode: 88 | ``` 89 | ./wuzapi --logtype json Nesse caso, color é irrelevante. 90 | ``` 91 | 92 | Com fuso horário: 93 | Defina TZ=America/Sao_Paulo ./wuzapi ... no seu shell, ou no Docker Compose environment: TZ=America/Sao_Paulo. 94 | 95 | ## Usage 96 | 97 | Na primeira execução, o sistema cria automaticamente um usuário "admin" com o token administrativo definido na variável de ambiente `WUZAPI_ADMIN_TOKEN` ou no parâmetro `-admintoken`. Este usuário pode ser usado para autenticação e para gerenciar outros usuários. 98 | 99 | Para interagir com a API, você deve incluir o cabeçalho `Token` nas requisições HTTP, contendo o token de autenticação do usuário. Você pode ter vários usuários (diferentes números de WhatsApp) no mesmo servidor. 100 | 101 | O daemon também serve alguns arquivos web estáticos, úteis para desenvolvimento/teste, que você pode acessar com seu navegador: 102 | 103 | * Uma referência da API Swagger em [/api](/api) 104 | * Uma página web de exemplo para conectar e escanear códigos QR em [/login](/login) (onde você precisará passar ?token=seu_token_aqui) 105 | 106 | ## ADMIN Actions 107 | 108 | Você pode listar, adicionar e excluir usuários usando os endpoints de administração. Para usar essa funcionalidade, você deve configurar o token de administrador de uma das seguintes formas: 109 | 110 | 1. Definir a variável de ambiente `WUZAPI_ADMIN_TOKEN` antes de iniciar o aplicativo 111 | ```shell 112 | export WUZAPI_ADMIN_TOKEN=seu_token_seguro 113 | ``` 114 | 115 | 2. Ou passar o parâmetro `-admintoken` na linha de comando 116 | ```shell 117 | ./wuzapi -admintoken=seu_token_seguro 118 | ``` 119 | 120 | Então você pode usar o endpoint `/admin/users` com o cabeçalho `Authorization` contendo o token para: 121 | - `GET /admin/users` - Listar todos os usuários 122 | - `POST /admin/users` - Criar um novo usuário 123 | - `DELETE /admin/users/{id}` - Remover um usuário 124 | 125 | O corpo JSON para criar um novo usuário deve conter: 126 | 127 | - `name` [string] : Nome do usuário 128 | - `token` [string] : Token de segurança para autorizar/autenticar este usuário 129 | - `webhook` [string] : URL para enviar eventos via POST (opcional) 130 | - `events` [string] : Lista de eventos separados por vírgula a serem recebidos (opcional) - Eventos válidos são: "Message", "ReadReceipt", "Presence", "HistorySync", "ChatPresence", "All" 131 | - `expiration` [int] : Timestamp de expiração (opcional, não é aplicado pelo sistema) 132 | 133 | ## API reference 134 | 135 | API calls should be made with content type json, and parameters sent into the 136 | request body, always passing the Token header for authenticating the request. 137 | 138 | Check the [API Reference](https://github.com/asternic/wuzapi/blob/main/API.md) 139 | 140 | ## License 141 | 142 | Copyright © 2022 Nicolás Gudiño 143 | 144 | [MIT](https://choosealicense.com/licenses/mit/) 145 | 146 | Permission is hereby granted, free of charge, to any person obtaining a copy of 147 | this software and associated documentation files (the "Software"), to deal in 148 | the Software without restriction, including without limitation the rights to 149 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 150 | of the Software, and to permit persons to whom the Software is furnished to do 151 | so, subject to the following conditions: 152 | 153 | The above copyright notice and this permission notice shall be included in all 154 | copies or substantial portions of the Software. 155 | 156 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 158 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 159 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 160 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 161 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 162 | SOFTWARE. 163 | 164 | ## Icon Attribution 165 | 166 | [Communication icons created by Vectors Market - 167 | Flaticon](https://www.flaticon.com/free-icons/communication) 168 | 169 | ## Legal 170 | 171 | This code is in no way affiliated with, authorized, maintained, sponsored or 172 | endorsed by WhatsApp or any of its affiliates or subsidiaries. This is an 173 | independent and unofficial software. Use at your own risk. 174 | 175 | ## Cryptography Notice 176 | 177 | This distribution includes cryptographic software. The country in which you 178 | currently reside may have restrictions on the import, possession, use, and/or 179 | re-export to another country, of encryption software. BEFORE using any 180 | encryption software, please check your country's laws, regulations and policies 181 | concerning the import, possession, or use, and re-export of encryption 182 | software, to see if this is permitted. See 183 | [http://www.wassenaar.org/](http://www.wassenaar.org/) for more information. 184 | 185 | The U.S. Government Department of Commerce, Bureau of Industry and Security 186 | (BIS), has classified this software as Export Commodity Control Number (ECCN) 187 | 5D002.C.1, which includes information security software using or performing 188 | cryptographic functions with asymmetric algorithms. The form and manner of this 189 | distribution makes it eligible for export under the License Exception ENC 190 | Technology Software Unrestricted (TSU) exception (see the BIS Export 191 | Administration Regulations, Section 740.13) for both object code and source 192 | code. 193 | 194 | 195 | -------------------------------------------------------------------------------- /docker-compose-swarm.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | wuzapi-server: 5 | image: setupautomatizado/wuzapi-server:latest 6 | networks: 7 | - network_public 8 | environment: 9 | - WUZAPI_ADMIN_TOKEN=H4Zbhw72PBKdTIgS 10 | - DB_USER=wuzapi 11 | - DB_PASSWORD=wuzapi 12 | - DB_NAME=wuzapi 13 | - DB_HOST=db 14 | - DB_PORT=5432 15 | - TZ=America/Sao_Paulo 16 | volumes: 17 | - wuzapi_dbdata:/app/dbdata 18 | - wuzapi_files:/app/files 19 | deploy: 20 | mode: replicated 21 | replicas: 1 22 | restart_policy: 23 | condition: on-failure 24 | placement: 25 | constraints: [node.role == manager] 26 | resources: 27 | limits: 28 | cpus: "1" 29 | memory: 512MB 30 | labels: 31 | - traefik.enable=true 32 | - traefik.http.routers.wuzapi-server.rule=Host(`api.wuzapi.app`) 33 | - traefik.http.routers.wuzapi-server.entrypoints=websecure 34 | - traefik.http.routers.wuzapi-server.priority=1 35 | - traefik.http.routers.wuzapi-server.tls.certresolver=letsencryptresolver 36 | - traefik.http.routers.wuzapi-server.service=wuzapi-server 37 | - traefik.http.services.wuzapi-server.loadbalancer.server.port=8080 38 | # healthcheck: 39 | # test: ["CMD", "curl", "-f", "http://localhost:8080/health"] 40 | # interval: 10s 41 | # timeout: 5s 42 | # retries: 3 43 | # start_period: 10s 44 | 45 | networks: 46 | network_public: 47 | name: network_public 48 | external: true 49 | 50 | volumes: 51 | wuzapi_dbdata: 52 | external: true 53 | name: wuzapi_dbdata 54 | wuzapi_files: 55 | external: true 56 | name: wuzapi_files -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | wuzapi-server: 3 | build: 4 | context: . 5 | dockerfile: Dockerfile 6 | ports: 7 | - "8080:8080" 8 | environment: 9 | - WUZAPI_ADMIN_TOKEN=H4Zbhw72PBKdTIgS 10 | - DB_USER=wuzapi 11 | - DB_PASSWORD=wuzapi 12 | - DB_NAME=wuzapi 13 | - DB_HOST=db 14 | - DB_PORT=5432 15 | - TZ=America/Sao_Paulo 16 | volumes: 17 | - ./dbdata:/app/dbdata 18 | - ./files:/app/files 19 | depends_on: 20 | - db 21 | networks: 22 | - wuzapi-network 23 | 24 | db: 25 | image: postgres:15 26 | environment: 27 | POSTGRES_USER: wuzapi 28 | POSTGRES_PASSWORD: wuzapi 29 | POSTGRES_DB: wuzapi 30 | ports: 31 | - "5432:5432" 32 | volumes: 33 | - db_data:/var/lib/postgresql/data 34 | networks: 35 | - wuzapi-network 36 | 37 | networks: 38 | wuzapi-network: 39 | driver: bridge 40 | 41 | volumes: 42 | dbdata: 43 | files: 44 | db_data: -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # WuzAPI Dashboard 2 | 3 | Interface de usuário para gerenciamento do WuzAPI. 4 | 5 | ## Requisitos 6 | 7 | - Node.js 14.x ou superior 8 | - npm 6.x ou superior 9 | 10 | ## Instalação 11 | 12 | 1. Clone o repositório 13 | 2. Navegue até o diretório do frontend: 14 | ```bash 15 | cd frontend 16 | ``` 17 | 3. Instale as dependências: 18 | ```bash 19 | npm install 20 | ``` 21 | 22 | ## Executando o Projeto 23 | 24 | Para iniciar o servidor de desenvolvimento: 25 | 26 | ```bash 27 | npm start 28 | ``` 29 | 30 | O aplicativo estará disponível em [http://localhost:3000](http://localhost:3000). 31 | 32 | ## Estrutura do Projeto 33 | 34 | ``` 35 | frontend/ 36 | ├── public/ # Arquivos estáticos 37 | ├── src/ 38 | │ ├── components/ # Componentes React 39 | │ ├── pages/ # Páginas da aplicação 40 | │ ├── App.tsx # Componente principal 41 | │ └── index.tsx # Ponto de entrada 42 | ├── package.json # Dependências e scripts 43 | └── tsconfig.json # Configuração do TypeScript 44 | ``` 45 | 46 | ## Funcionalidades 47 | 48 | - Dashboard com visão geral das instâncias 49 | - Gerenciamento de instâncias (iniciar/parar) 50 | - Configurações do sistema 51 | - Interface responsiva e moderna 52 | 53 | ## Desenvolvimento 54 | 55 | Para criar uma build de produção: 56 | 57 | ```bash 58 | npm run build 59 | ``` 60 | 61 | Para testar a aplicação: 62 | 63 | ```bash 64 | npm test 65 | ``` -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wuzapi-frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/react": "^11.11.3", 7 | "@emotion/styled": "^11.11.0", 8 | "@mui/icons-material": "^5.15.10", 9 | "@mui/material": "^5.15.10", 10 | "@testing-library/jest-dom": "^5.17.0", 11 | "@testing-library/react": "^13.4.0", 12 | "@testing-library/user-event": "^13.5.0", 13 | "@types/jest": "^27.5.2", 14 | "@types/node": "^16.18.80", 15 | "@types/react": "^18.2.55", 16 | "@types/react-dom": "^18.2.19", 17 | "@types/swagger-ui-react": "^5.18.0", 18 | "@types/uuid": "^10.0.0", 19 | "axios": "^1.6.7", 20 | "react": "^18.2.0", 21 | "react-dom": "^18.2.0", 22 | "react-router-dom": "^6.22.0", 23 | "react-scripts": "5.0.1", 24 | "swagger-ui-react": "^5.20.8", 25 | "typescript": "^4.9.5", 26 | "uuid": "^11.1.0", 27 | "web-vitals": "^2.1.4" 28 | }, 29 | "scripts": { 30 | "start": "set PORT=3001 && react-scripts start", 31 | "build": "react-scripts build", 32 | "test": "react-scripts test", 33 | "eject": "react-scripts eject" 34 | }, 35 | "eslintConfig": { 36 | "extends": [ 37 | "react-app", 38 | "react-app/jest" 39 | ] 40 | }, 41 | "browserslist": { 42 | "production": [ 43 | ">0.2%", 44 | "not dead", 45 | "not op_mini all" 46 | ], 47 | "development": [ 48 | "last 1 chrome version", 49 | "last 1 firefox version", 50 | "last 1 safari version" 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | WuzAPI Dashboard 15 | 19 | 20 | 21 | 22 |
23 | 24 | -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "WuzAPI", 3 | "name": "WuzAPI Dashboard", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "zpro.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } -------------------------------------------------------------------------------- /frontend/public/zpro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pedroherpeto/wuzapi/e1d689e33dcdf9b6d68fd5d6d074fe39fc4d0ab3/frontend/public/zpro.png -------------------------------------------------------------------------------- /frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import { Routes, Route, useNavigate, useLocation, Navigate } from 'react-router-dom'; 3 | import { Box } from '@mui/material'; 4 | import { AuthProvider, useAuth } from './contexts/AuthContext'; 5 | import ProtectedRoute from './components/ProtectedRoute'; 6 | import Navbar from './components/Navbar'; 7 | import Dashboard from './pages/Dashboard'; 8 | import Instances from './pages/Instances'; 9 | import Login from './pages/Login'; 10 | import ApiDocs from './pages/ApiDocs'; 11 | import Footer from './components/Footer'; 12 | 13 | const Layout = ({ children }: { children: React.ReactNode }) => ( 14 | 21 | 22 | 27 | {children} 28 | 29 | 37 |