mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-12-19 03:42:23 -06:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a6301c2af | ||
|
|
bca830dc54 | ||
|
|
77bde5325e | ||
|
|
bdca506dd4 | ||
|
|
34faaa28ca | ||
|
|
a08d433d0a |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,3 +1,14 @@
|
||||
# 1.1.1 (2023-06-28 10:27)
|
||||
|
||||
### Features
|
||||
|
||||
* Added group invitation sending
|
||||
* Added webhook configuration per event in the individual instance registration
|
||||
|
||||
### Fixed
|
||||
|
||||
* Adjust dockerfile variables
|
||||
|
||||
# 1.1.0 (2023-06-21 11:17)
|
||||
|
||||
### Features
|
||||
|
||||
87
Docker/.env
87
Docker/.env
@@ -1,87 +0,0 @@
|
||||
CORS_ORIGIN='*' # Or separate by commas - ex.: 'yourdomain1.com, yourdomain2.com'
|
||||
CORS_METHODS='POST,GET,PUT,DELETE'
|
||||
CORS_CREDENTIALS=true
|
||||
|
||||
# Determine the logs to be displayed
|
||||
LOG_LEVEL='ERROR,WARN,DEBUG,INFO,LOG,VERBOSE,DARK'
|
||||
LOG_COLOR=true
|
||||
|
||||
# Determine how long the instance should be deleted from memory in case of no connection.
|
||||
# Default time: 5 minutes
|
||||
# If you don't even want an expiration, enter the value false
|
||||
DEL_INSTANCE=5
|
||||
|
||||
# Temporary data storage
|
||||
STORE_MESSAGES=true
|
||||
STORE_MESSAGE_UP=true
|
||||
STORE_CONTACTS=false
|
||||
STORE_CHATS=false
|
||||
|
||||
CLEAN_STORE_CLEANING_INTERVAL=7200 # seconds ===2h
|
||||
CLEAN_STORE_MESSAGES=true
|
||||
CLEAN_STORE_MESSAGE_UP=true
|
||||
CLEAN_STORE_CONTACTS=false
|
||||
CLEAN_STORE_CHATS=false
|
||||
|
||||
# Permanent data storage
|
||||
DATABASE_ENABLED=false
|
||||
DATABASE_CONNECTION_URI='<uri>'
|
||||
DATABASE_CONNECTION_DB_PREFIX_NAME='evolution'
|
||||
DATABASE_SAVE_DATA_INSTANCE=false
|
||||
DATABASE_SAVE_DATA_OLD_MESSAGE=false
|
||||
DATABASE_SAVE_DATA_NEW_MESSAGE=true
|
||||
DATABASE_SAVE_MESSAGE_UPDATE=true
|
||||
DATABASE_SAVE_DATA_CONTACTS=true
|
||||
DATABASE_SAVE_DATA_CHATS=true
|
||||
|
||||
REDIS_ENABLED=true
|
||||
REDIS_URI='<uri>/1'
|
||||
REDIS_PREFIX_KEY='evolution'
|
||||
|
||||
# Webhook Settings
|
||||
## Define a global webhook that will listen for enabled events from all instances
|
||||
WEBHOOK_GLOBAL_URL='<url>'
|
||||
WEBHOOK_GLOBAL_ENABLED=false
|
||||
WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false
|
||||
## Set the events you want to hear
|
||||
WEBHOOK_EVENTS_STATUS_INSTANCE=true
|
||||
WEBHOOK_EVENTS_APPLICATION_STARTUP=true
|
||||
WEBHOOK_EVENTS_QRCODE_UPDATED=true
|
||||
WEBHOOK_EVENTS_MESSAGES_SET=true
|
||||
WEBHOOK_EVENTS_MESSAGES_UPDATE=true
|
||||
WEBHOOK_EVENTS_MESSAGES_UPSERT=true
|
||||
WEBHOOK_EVENTS_SEND_MESSAGE=true
|
||||
WEBHOOK_EVENTS_CONTACTS_SET=true
|
||||
WEBHOOK_EVENTS_CONTACTS_UPSERT=true
|
||||
WEBHOOK_EVENTS_CONTACTS_UPDATE=true
|
||||
WEBHOOK_EVENTS_PRESENCE_UPDATE=true
|
||||
WEBHOOK_EVENTS_CHATS_SET=true
|
||||
WEBHOOK_EVENTS_CHATS_UPSERT=true
|
||||
WEBHOOK_EVENTS_CHATS_UPDATE=true
|
||||
WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
||||
WEBHOOK_EVENTS_GROUPS_UPSERT=false
|
||||
WEBHOOK_EVENTS_GROUPS_UPDATE=false
|
||||
WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=false
|
||||
## This event fires every time a new token is requested via the refresh route
|
||||
WEBHOOK_EVENTS_NEW_JWT_TOKEN=true
|
||||
|
||||
CONFIG_SESSION_PHONE_CLIENT='Evolution API'
|
||||
CONFIG_SESSION_PHONE_NAME='Chrome'
|
||||
|
||||
# Set qrcode display limit
|
||||
QRCODE_LIMIT=6
|
||||
|
||||
# Defines an authentication type for the api
|
||||
AUTHENTICATION_TYPE='jwt' # or 'apikey'
|
||||
## Define a global apikey to access all instances.
|
||||
### OBS: This key must be inserted in the request header to create an instance.
|
||||
AUTHENTICATION_API_KEY='t8OOEeISKzpmc3jjcMqBWYSaJsafdefer'
|
||||
AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true
|
||||
## Set the secret key to encrypt and decrypt your token and its expiration time
|
||||
AUTHENTICATION_JWT_EXPIRIN_IN=3600 # seconds - 3600s ===1h | zero (0) - never expires
|
||||
AUTHENTICATION_JWT_SECRET='L0YWtjb2w554WFqPG'
|
||||
|
||||
AUTHENTICATION_INSTANCE_NAME='evolution'
|
||||
AUTHENTICATION_INSTANCE_WEBHOOK_URL='<url>'
|
||||
AUTHENTICATION_INSTANCE_MODE='container' # or 'server'
|
||||
AUTHENTICATION_INSTANCE_WEBHOOK_BY_EVENTS=false
|
||||
27
Docker/mongodb/docker-compose.yaml
Normal file
27
Docker/mongodb/docker-compose.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
version: '3.3'
|
||||
|
||||
networks:
|
||||
evolution-net:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
mongodb:
|
||||
container_name: mongodb
|
||||
image: mongo
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution_mongodb_data:/data/db
|
||||
- evolution_mongodb_configdb:/data/configdb
|
||||
ports:
|
||||
- 27017:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: root
|
||||
networks:
|
||||
- evolution-net
|
||||
expose:
|
||||
- 27017
|
||||
|
||||
volumes:
|
||||
evolution_mongodb_data:
|
||||
evolution_mongodb_configdb:
|
||||
27
Docker/redis/docker-compose.yaml
Normal file
27
Docker/redis/docker-compose.yaml
Normal file
@@ -0,0 +1,27 @@
|
||||
version: '3.3'
|
||||
|
||||
networks:
|
||||
evolution-net:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:latest
|
||||
command: >
|
||||
redis-server
|
||||
--port 6379
|
||||
--appendonly yes
|
||||
--save 900 1
|
||||
--save 300 10
|
||||
--save 60 10000
|
||||
--appendfsync everysec
|
||||
volumes:
|
||||
- evolution_redis:/data
|
||||
container_name: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
networks:
|
||||
- evolution-net
|
||||
|
||||
volumes:
|
||||
evolution_redis:
|
||||
@@ -49,7 +49,6 @@ ENV WEBHOOK_GLOBAL_URL=$WEBHOOK_GLOBAL_URL
|
||||
ENV WEBHOOK_GLOBAL_ENABLED=$WEBHOOK_GLOBAL_ENABLED
|
||||
ENV WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=$WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS
|
||||
|
||||
ENV WEBHOOK_EVENTS_STATUS_INSTANCE=$WEBHOOK_EVENTS_STATUS_INSTANCE
|
||||
ENV WEBHOOK_EVENTS_APPLICATION_STARTUP=$WEBHOOK_EVENTS_APPLICATION_STARTUP
|
||||
ENV WEBHOOK_EVENTS_QRCODE_UPDATED=$WEBHOOK_EVENTS_QRCODE_UPDATED
|
||||
ENV WEBHOOK_EVENTS_MESSAGES_SET=$WEBHOOK_EVENTS_MESSAGES_SET
|
||||
@@ -71,7 +70,7 @@ ENV WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=$WEBHOOK_EVENTS_GROUP_PARTICIPANTS_
|
||||
ENV WEBHOOK_EVENTS_NEW_JWT_TOKEN=$WEBHOOK_EVENTS_NEW_JWT_TOKEN
|
||||
|
||||
ENV CONFIG_SESSION_PHONE_CLIENT=$CONFIG_SESSION_PHONE_CLIENT
|
||||
ENV CONFIG_SESSION_PHONE_NAME="Chrome"
|
||||
ENV CONFIG_SESSION_PHONE_NAME=$CONFIG_SESSION_PHONE_NAME
|
||||
|
||||
ENV QRCODE_LIMIT=$QRCODE_LIMIT
|
||||
|
||||
@@ -86,7 +85,6 @@ ENV AUTHENTICATION_JWT_SECRET="L=0YWt]b2w[WF>#>:&E`"
|
||||
ENV AUTHENTICATION_INSTANCE_NAME=$AUTHENTICATION_INSTANCE_NAME
|
||||
ENV AUTHENTICATION_INSTANCE_WEBHOOK_URL=$AUTHENTICATION_INSTANCE_WEBHOOK_URL
|
||||
ENV AUTHENTICATION_INSTANCE_MODE=$AUTHENTICATION_INSTANCE_MODE
|
||||
ENV AUTHENTICATION_INSTANCE_WEBHOOK_BY_EVENTS=$AUTHENTICATION_INSTANCE_WEBHOOK_BY_EVENTS
|
||||
|
||||
RUN npm install
|
||||
|
||||
|
||||
254
README.md
254
README.md
@@ -2,8 +2,8 @@
|
||||
|
||||
<div align="center">
|
||||
|
||||
<!-- [](#)-->
|
||||
<!-- [](#) -->
|
||||
[](https://doc.evolution-api.com)
|
||||
[](https://doc.evolution-api.com)
|
||||
[](./LICENSE)
|
||||
[](https://app.picpay.com/user/davidsongomes1998)
|
||||
|
||||
@@ -16,256 +16,6 @@
|
||||
This project is based on the [CodeChat](https://github.com/code-chat-br/whatsapp-api). The original project is an implementation of [Baileys](https://github.com/WhiskeySockets/Baileys), serving as a Restful API service that controls WhatsApp functions.</br>
|
||||
The code allows the creation of multiservice chats, service bots, or any other system that utilizes WhatsApp. The documentation provides instructions on how to set up and use the project, as well as additional information about its features and configuration options.
|
||||
|
||||
## Infrastructure
|
||||
|
||||
### Nvm installation
|
||||
|
||||
```sh
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
||||
# or
|
||||
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
||||
```
|
||||
>
|
||||
> After finishing, restart the terminal to load the new information.
|
||||
>
|
||||
|
||||
### Docker installation \[optional\]
|
||||
|
||||
```sh
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh
|
||||
|
||||
sudo sh get-docker.sh
|
||||
|
||||
sudo usermod -aG docker ${USER}
|
||||
```
|
||||
### Nodejs installation
|
||||
|
||||
```sh
|
||||
nvm install 16.18.1
|
||||
```
|
||||
|
||||
### pm2 installation
|
||||
```sh
|
||||
npm i -g pm2
|
||||
```
|
||||
|
||||
```sh
|
||||
docker --version
|
||||
|
||||
node --version
|
||||
```
|
||||
## MongoDb [optional]
|
||||
|
||||
After installing docker and docker-compose, up the container.
|
||||
- [compose from mongodb](./mongodb/docker-compose.yaml)
|
||||
|
||||
In the same directory where the file is located, run the following command:
|
||||
```sh
|
||||
bash docker.sh
|
||||
```
|
||||
Using the database is optional.
|
||||
|
||||
## Application startup
|
||||
|
||||
Cloning the Repository
|
||||
```
|
||||
git clone https://github.com/EvolutionAPI/evolution-api.git
|
||||
```
|
||||
|
||||
Go to the project directory and install all dependencies.</br>
|
||||
```sh
|
||||
cd whatsapp-api
|
||||
|
||||
npm i
|
||||
```
|
||||
|
||||
Finally, run the command below to start the application:
|
||||
```sh
|
||||
# Under development
|
||||
npm run start
|
||||
|
||||
# In production
|
||||
npm run start:prod
|
||||
|
||||
# pm2
|
||||
pm2 start 'npm run start:prod' --name ApiEvolution
|
||||
```
|
||||
## Authentication
|
||||
|
||||
You can define two authentication **types** for the routes in the **[env file](./src/dev-env.yml)**.
|
||||
Authentications must be inserted in the request header.
|
||||
|
||||
1. **apikey**
|
||||
|
||||
2. **jwt:** A JWT is a standard for authentication and information exchange defined with a signature.
|
||||
|
||||
> Authentications are generated at instance creation time.
|
||||
|
||||
**Note:** There is also the possibility to define a global api key, which can access and control all instances.
|
||||
|
||||
### Connection
|
||||
|
||||
#### Create an instance
|
||||
|
||||
##### HTTP
|
||||
|
||||
> *NOTE:* This key must be inserted in the request header to create an instance.
|
||||
|
||||
```http
|
||||
POST /instance/create HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Content-Type: application/json
|
||||
apikey: t8OOEeISKzpmc3jjcMqBWYSaJH2PIxns
|
||||
|
||||
```
|
||||
##### cURL
|
||||
|
||||
```bash
|
||||
curl --location --request POST 'http://localhost:8080/instance/create' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'apikey: t8OOEeISKzpmc3jjcMqBWYSaJH2PIxns' \
|
||||
--data-raw '{
|
||||
"instanceName": "evolution"
|
||||
}'
|
||||
```
|
||||
### Response
|
||||
|
||||
```ts
|
||||
{
|
||||
"instance": {
|
||||
"instanceName": "evolution",
|
||||
"status": "created"
|
||||
},
|
||||
"hash": {
|
||||
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. [...]"
|
||||
|
||||
// or
|
||||
// "apikey": "88513847-1B0E-4188-8D76-4A2750C9B6C3"
|
||||
}
|
||||
}
|
||||
```
|
||||
#### Connection with qrcode
|
||||
|
||||
##### HTTP
|
||||
|
||||
```http
|
||||
GET /instance/connect/evolution HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. [...]
|
||||
```
|
||||
```http
|
||||
GET /instance/connect/evolution HTTP/1.1
|
||||
Host: localhost:8080
|
||||
apikey: 88513847-1B0E-4188-8D76-4A2750C9B6C3
|
||||
```
|
||||
##### cURL
|
||||
|
||||
```bash
|
||||
curl --location --request GET 'http://localhost:8080/instance/connect/evolution' \
|
||||
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. [...]'
|
||||
```
|
||||
```bash
|
||||
curl --location --request GET 'http://localhost:8080/instance/connect/evolution' \
|
||||
--header 'apikey: 88513847-1B0E-4188-8D76-4A2750C9B6C3'
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```ts
|
||||
{
|
||||
"code": "2@nXSUgRJSBY6T0XJmiFKZ0 [...] ,XsgJhJHYa+0MPpXANdPHHt6Ke/I7O2QyXT/Lsge0uSg=",
|
||||
"base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhE [...] LkMtqAAAAABJRU5ErkJggg=="
|
||||
}
|
||||
```
|
||||
|
||||
### App in Docker
|
||||
- [docker run](./docker.sh)
|
||||
- [docker-compose](./docker-compose.yml)
|
||||
- [env for docker](./Docker/.env)
|
||||
- [DockerHub Evolution API](https://hub.docker.com/repository/docker/davidsongomes/evolution-api)
|
||||
|
||||
After building the application, in the same directory as the files above, run the following command:
|
||||
```sh
|
||||
docker-compose up
|
||||
```
|
||||
## Send Messages
|
||||
| | |
|
||||
|-----|---|
|
||||
| Send Text | ✔ |
|
||||
| Send Template | ❌ |
|
||||
| Send Media: audio - video - image - document - gif <br></br>base64: ```true``` | ✔ |
|
||||
| Send Media File | ❌ |
|
||||
| Send Audio type WhatsApp | ✔ |
|
||||
| Send Location | ✔ |
|
||||
| Send Link Preview | ✔ |
|
||||
| Send Contact | ✔ |
|
||||
| Send Reaction - emoji | ✔ |
|
||||
| Send Poll Message | ✔ |
|
||||
| Send Buttons (Deprecated) | ❌ |
|
||||
| Send List (Deprecated) | ❌ |
|
||||
|
||||
## Postman collections
|
||||
- [Postman Json](./postman.json)
|
||||
|
||||
## Webhook Events
|
||||
|
||||
| Name | Event | TypeData | Description |
|
||||
|------|-------|-----------|------------|
|
||||
| APPLICATION_STARTUP | application.startup | json | Notifies you when a application startup |
|
||||
| QRCODE_UPDATED | qrcode.updated | json | Sends the base64 of the qrcode for reading |
|
||||
| CONNECTION_UPDATE | connection.update | json | Informs the status of the connection with whatsapp |
|
||||
| MESSAGES_SET | message.set | json | Sends a list of all your messages uploaded on whatsapp</br>This event occurs only once |
|
||||
| MESSAGES_UPSERT | message.upsert | json | Notifies you when a message is received |
|
||||
| MESSAGES_UPDATE | message.update | json | Tells you when a message is updated |
|
||||
| SEND_MESSAGE | send.message | json | Notifies when a message is sent |
|
||||
| CONTACTS_SET | contacts.set | json | Performs initial loading of all contacts</br>This event occurs only once |
|
||||
| CONTACTS_UPSERT | contacts.upsert | json | Reloads all contacts with additional information</br>This event occurs only once |
|
||||
| CONTACTS_UPDATE | contacts.update | json | Informs you when the chat is updated |
|
||||
| PRESENCE_UPDATE | presence.update | json | Informs if the user is online, if he is performing some action like writing or recording and his last seen</br>'unavailable' | 'available' | 'composing' | 'recording' | 'paused' |
|
||||
| CHATS_SET | chats.set | json | Send a list of all loaded chats |
|
||||
| CHATS_UPDATE | chats.update | json | Informs you when the chat is updated |
|
||||
| CHATS_UPSERT | chats.upsert | json | Sends any new chat information |
|
||||
| GROUPS_UPSERT | groups.upsert | JSON | Notifies when a group is created |
|
||||
| GROUPS_UPDATE | groups.update | JSON | Notifies when a group has its information updated |
|
||||
| GROUP_PARTICIPANTS_UPDATE | group-participants.update | JSON | Notifies when an action occurs involving a participant</br>'add' | 'remove' | 'promote' | 'demote' |
|
||||
| NEW_TOKEN | new.jwt | JSON | Notifies when the token (jwt) is updated
|
||||
|
||||
## Webhook Routes
|
||||
When enabling the WEBHOOK_BY_EVENTS options in the global and local webhooks, the following paths will be added at the end of the webhook.
|
||||
<br><br>
|
||||
Example:
|
||||
|
||||
https://sub.domain.com/webhook-test/exclusive-webhook-code/qrcode-updated
|
||||
|
||||
| Name | Path |
|
||||
|------|-------|
|
||||
| APPLICATION_STARTUP | /application-startup |
|
||||
| QRCODE_UPDATED | /qrcode-updated |
|
||||
| CONNECTION_UPDATE | /connection-update |
|
||||
| MESSAGES_SET | /messages-set |
|
||||
| MESSAGES_UPSERT | /messages-upsert |
|
||||
| MESSAGES_UPDATE | /messages-update |
|
||||
| SEND_MESSAGE | /send-message |
|
||||
| CONTACTS_SET | /contacts-set |
|
||||
| CONTACTS_UPSERT | /contacts-upsert |
|
||||
| CONTACTS_UPDATE | /contacts-update |
|
||||
| PRESENCE_UPDATE | /presence-update |
|
||||
| CHATS_SET | /chats-set |
|
||||
| CHATS_UPDATE | /chats-update |
|
||||
| CHATS_UPSERT | /chats-upsert |
|
||||
| GROUPS_UPSERT | /groups-upsert |
|
||||
| GROUPS_UPDATE | /groups-update |
|
||||
| GROUP_PARTICIPANTS_UPDATE | /groups-participants-update |
|
||||
| NEW_TOKEN | /new-token |
|
||||
## Env File
|
||||
|
||||
See additional settings that can be applied through the **env** file by clicking **[here](./src/dev-env.yml)**.
|
||||
|
||||
> **⚠️Attention⚠️:** rename the **dev-env.yml** file to **env.yml**.
|
||||
|
||||
## SSL
|
||||
|
||||
To install the SSL certificate, follow the **[instructions](https://certbot.eff.org/instructions?ws=other&os=ubuntufocal)** below.
|
||||
## SSL
|
||||
|
||||
To install the SSL certificate, follow the **[instructions](https://certbot.eff.org/instructions?ws=other&os=ubuntufocal)** below.
|
||||
|
||||
@@ -13,9 +13,6 @@ services:
|
||||
volumes:
|
||||
- evolution_instances:/evolution/instances
|
||||
- evolution_store:/evolution/store
|
||||
depends_on:
|
||||
- mongodb
|
||||
- redis
|
||||
environment:
|
||||
# Determine how long the instance should be deleted from memory in case of no connection.
|
||||
# Default time: 5 minutes
|
||||
@@ -32,7 +29,7 @@ services:
|
||||
- CLEAN_STORE_CONTACTS=true
|
||||
- CLEAN_STORE_CHATS=true
|
||||
# Permanent data storage
|
||||
- DATABASE_ENABLED=true
|
||||
- DATABASE_ENABLED=false
|
||||
- DATABASE_CONNECTION_URI=mongodb://root:root@mongodb:27017/?authSource=admin&readPreference=primary&ssl=false&directConnection=true
|
||||
- DATABASE_CONNECTION_DB_PREFIX_NAME=evolution
|
||||
# Choose the data you want to save in the application's database or store
|
||||
@@ -42,23 +39,22 @@ services:
|
||||
- DATABASE_SAVE_MESSAGE_UPDATE=true
|
||||
- DATABASE_SAVE_DATA_CONTACTS=true
|
||||
- DATABASE_SAVE_DATA_CHATS=true
|
||||
- REDIS_ENABLED=true
|
||||
- REDIS_URI=redis://redis:6379
|
||||
- REDIS_ENABLED=false
|
||||
- REDIS_URI=redis://redis:6379/1
|
||||
- REDIS_PREFIX_KEY=evolution
|
||||
# Webhook Settings
|
||||
# Define a global webhook that will listen for enabled events from all instances
|
||||
- WEBHOOK_GLOBAL_URL=url
|
||||
- WEBHOOK_GLOBAL_URL=<url>
|
||||
- WEBHOOK_GLOBAL_ENABLED=false
|
||||
# With this option activated, you work with a url per webhook event, respecting the global url and the name of each event
|
||||
- WEBHOOK_GLOBAL_WEBHOOK_BY_EVENTS=false
|
||||
# Automatically maps webhook paths
|
||||
# Set the events you want to hear
|
||||
- WEBHOOK_EVENTS_STATUS_INSTANCE=true
|
||||
- WEBHOOK_EVENTS_APPLICATION_STARTUP=false
|
||||
- WEBHOOK_EVENTS_QRCODE_UPDATED=true
|
||||
- WEBHOOK_EVENTS_MESSAGES_SET=true
|
||||
- WEBHOOK_EVENTS_MESSAGES_UPDATE=true
|
||||
- WEBHOOK_EVENTS_MESSAGES_UPSERT=true
|
||||
- WEBHOOK_EVENTS_MESSAGES_UPDATE=true
|
||||
- WEBHOOK_EVENTS_SEND_MESSAGE=true
|
||||
- WEBHOOK_EVENTS_CONTACTS_SET=true
|
||||
- WEBHOOK_EVENTS_CONTACTS_UPSERT=true
|
||||
@@ -67,14 +63,16 @@ services:
|
||||
- WEBHOOK_EVENTS_CHATS_SET=true
|
||||
- WEBHOOK_EVENTS_CHATS_UPSERT=true
|
||||
- WEBHOOK_EVENTS_CHATS_UPDATE=true
|
||||
- WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
||||
- WEBHOOK_EVENTS_CHATS_DELETE=true
|
||||
- WEBHOOK_EVENTS_GROUPS_UPSERT=true
|
||||
- WEBHOOK_EVENTS_GROUPS_UPDATE=true
|
||||
- WEBHOOK_EVENTS_GROUP_PARTICIPANTS_UPDATE=true
|
||||
- WEBHOOK_EVENTS_CONNECTION_UPDATE=true
|
||||
# This event fires every time a new token is requested via the refresh route
|
||||
- WEBHOOK_EVENTS_NEW_JWT_TOKEN=true
|
||||
# Name that will be displayed on smartphone connection
|
||||
- CONFIG_SESSION_PHONE_CLIENT="Evolution API"
|
||||
- CONFIG_SESSION_PHONE_CLIENT=Evolution API
|
||||
- CONFIG_SESSION_PHONE_NAME=chrome # chrome | firefox | edge | opera | safari
|
||||
# Set qrcode display limit
|
||||
- QRCODE_LIMIT=30
|
||||
# Defines an authentication type for the api
|
||||
@@ -88,56 +86,16 @@ services:
|
||||
- AUTHENTICATION_JWT_EXPIRIN_IN=0 # seconds - 3600s === 1h | zero (0) - never expires
|
||||
# Set the instance name and webhook url to create an instance in init the application
|
||||
# With this option activated, you work with a url per webhook event, respecting the local url and the name of each event
|
||||
- AUTHENTICATION_INSTANCE_WEBHOOK_BY_EVENTS=false
|
||||
- AUTHENTICATION_INSTANCE_MODE=server # container or server
|
||||
# if you are using container mode, set the container name and the webhook url to default instance
|
||||
- AUTHENTICATION_INSTANCE_NAME=evolution
|
||||
- AUTHENTICATION_INSTANCE_WEBHOOK_URL=url
|
||||
- AUTHENTICATION_INSTANCE_WEBHOOK_URL=<url>
|
||||
command: ['node', './dist/src/main.js']
|
||||
networks:
|
||||
- evolution-net
|
||||
expose:
|
||||
- 8080
|
||||
|
||||
mongodb:
|
||||
container_name: mongodb
|
||||
image: mongo
|
||||
restart: always
|
||||
volumes:
|
||||
- evolution_mongodb_data:/data/db
|
||||
- evolution_mongodb_configdb:/data/configdb
|
||||
ports:
|
||||
- 27017:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
MONGO_INITDB_ROOT_PASSWORD: root
|
||||
networks:
|
||||
- evolution-net
|
||||
expose:
|
||||
- 27017
|
||||
|
||||
redis:
|
||||
image: redis:latest
|
||||
command: >
|
||||
redis-server
|
||||
--port 6379
|
||||
--appendonly yes
|
||||
--save 900 1
|
||||
--save 300 10
|
||||
--save 60 10000
|
||||
--appendfsync everysec
|
||||
volumes:
|
||||
- evolution_redis:/data
|
||||
container_name: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
networks:
|
||||
- evolution-net
|
||||
|
||||
|
||||
volumes:
|
||||
evolution_instances:
|
||||
evolution_store:
|
||||
evolution_mongodb_data:
|
||||
evolution_mongodb_configdb:
|
||||
evolution_redis:
|
||||
evolution_store:
|
||||
10
docker.sh
10
docker.sh
@@ -8,10 +8,12 @@ then
|
||||
docker network create -d bridge ${NET}
|
||||
fi
|
||||
|
||||
sudo mkdir -p ./docker-data/instances
|
||||
sudo mkdir -p ./docker-data/mongodb
|
||||
sudo mkdir -p ./docker-data/mongodb/data
|
||||
sudo mkdir -p ./docker-data/mongodb/configdb
|
||||
# sudo mkdir -p ./docker-data/instances
|
||||
# sudo mkdir -p ./docker-data/mongodb
|
||||
# sudo mkdir -p ./docker-data/mongodb/data
|
||||
# sudo mkdir -p ./docker-data/mongodb/configdb
|
||||
# sudo mkdir -p ./docker-data/redis
|
||||
# sudo mkdir -p ./docker-data/redis/data
|
||||
|
||||
docker build -t ${IMAGE} .
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
version: '3.8'
|
||||
|
||||
networks:
|
||||
api-net:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
mongodb:
|
||||
container_name: mongodb
|
||||
|
||||
# This image already has a single replica set
|
||||
image: mongo
|
||||
|
||||
restart: always
|
||||
volumes:
|
||||
# sudo mkdir -p /data/mongodb
|
||||
- /data/mongodb:/data/db
|
||||
ports:
|
||||
- 26712:27017
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: root
|
||||
# Set a password to access the bank
|
||||
MONGO_INITDB_ROOT_PASSWORD: <password>
|
||||
networks:
|
||||
- api-net
|
||||
expose:
|
||||
- 26712
|
||||
@@ -87,7 +87,6 @@ export type Instance = {
|
||||
NAME: string;
|
||||
WEBHOOK_URL: string;
|
||||
MODE: string;
|
||||
WEBHOOK_BY_EVENTS: boolean;
|
||||
};
|
||||
export type Auth = {
|
||||
API_KEY: ApiKey;
|
||||
@@ -263,8 +262,6 @@ export class ConfigService {
|
||||
NAME: process.env.AUTHENTICATION_INSTANCE_NAME,
|
||||
WEBHOOK_URL: process.env.AUTHENTICATION_INSTANCE_WEBHOOK_URL,
|
||||
MODE: process.env.AUTHENTICATION_INSTANCE_MODE,
|
||||
WEBHOOK_BY_EVENTS:
|
||||
process.env.AUTHENTICATION_INSTANCE_WEBHOOK_BY_EVENTS === 'true',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ LOG:
|
||||
# Determine how long the instance should be deleted from memory in case of no connection.
|
||||
# Default time: 5 minutes
|
||||
# If you don't even want an expiration, enter the value false
|
||||
DEL_INSTANCE: false # or false
|
||||
DEL_INSTANCE: 5 # or false
|
||||
|
||||
# Temporary data storage
|
||||
STORE:
|
||||
@@ -112,7 +112,7 @@ WEBHOOK:
|
||||
CONFIG_SESSION_PHONE:
|
||||
# Name that will be displayed on smartphone connection
|
||||
CLIENT: 'Evolution API'
|
||||
NAME: Chrome # firefox | edge | opera | safari
|
||||
NAME: chrome # chrome | firefox | edge | opera | safari
|
||||
|
||||
# Set qrcode display limit
|
||||
QRCODE:
|
||||
@@ -120,11 +120,11 @@ QRCODE:
|
||||
|
||||
# Defines an authentication type for the api
|
||||
AUTHENTICATION:
|
||||
TYPE: apikey # or jwt apikey
|
||||
TYPE: apikey # jwt or apikey
|
||||
# Define a global apikey to access all instances
|
||||
API_KEY:
|
||||
# OBS: This key must be inserted in the request header to create an instance.
|
||||
KEY: B6D711FC-DE4D-4FD5-9365-44120E713976
|
||||
KEY: B6D711FCDE4D4FD5936544120E713976
|
||||
# Expose the api key on return from fetch instances
|
||||
EXPOSE_IN_FETCH_INSTANCES: true
|
||||
# Set the secret key to encrypt and decrypt your token and its expiration time.
|
||||
@@ -134,7 +134,6 @@ AUTHENTICATION:
|
||||
# Set the instance name and webhook url to create an instance in init the application
|
||||
INSTANCE:
|
||||
# With this option activated, you work with a url per webhook event, respecting the local url and the name of each event
|
||||
WEBHOOK_BY_EVENTS: false
|
||||
MODE: server # container or server
|
||||
# if you are using container mode, set the container name and the webhook url to default instance
|
||||
NAME: evolution
|
||||
|
||||
@@ -27,6 +27,7 @@ export const instanceNameSchema: JSONSchema7 = {
|
||||
properties: {
|
||||
instanceName: { type: 'string' },
|
||||
webhook: { type: 'string' },
|
||||
webhook_by_events: { type: 'boolean' },
|
||||
events: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
@@ -665,6 +666,28 @@ export const groupJidSchema: JSONSchema7 = {
|
||||
...isNotEmpty('groupJid'),
|
||||
};
|
||||
|
||||
export const groupSendInviteSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
properties: {
|
||||
groupJid: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
numbers: {
|
||||
type: 'array',
|
||||
minItems: 1,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: 'string',
|
||||
minLength: 10,
|
||||
pattern: '\\d+',
|
||||
description: '"numbers" must be an array of numeric strings',
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['groupJid', 'description', 'numbers'],
|
||||
...isNotEmpty('groupJid', 'description', 'numbers'),
|
||||
};
|
||||
|
||||
export const groupInviteSchema: JSONSchema7 = {
|
||||
$id: v4(),
|
||||
type: 'object',
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
GroupInvite,
|
||||
GroupJid,
|
||||
GroupPictureDto,
|
||||
GroupSendInvite,
|
||||
GroupSubjectDto,
|
||||
GroupToggleEphemeralDto,
|
||||
GroupUpdateParticipantDto,
|
||||
@@ -56,10 +57,8 @@ export class GroupController {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].inviteInfo(inviteCode);
|
||||
}
|
||||
|
||||
public async acceptInvite(instance: InstanceDto, inviteCode: GroupInvite) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].acceptInvite(
|
||||
inviteCode,
|
||||
);
|
||||
public async sendInvite(instance: InstanceDto, data: GroupSendInvite) {
|
||||
return await this.waMonitor.waInstances[instance.instanceName].sendInvite(data);
|
||||
}
|
||||
|
||||
public async revokeInviteCode(instance: InstanceDto, groupJid: GroupJid) {
|
||||
|
||||
@@ -26,6 +26,7 @@ export class InstanceController {
|
||||
public async createInstance({
|
||||
instanceName,
|
||||
webhook,
|
||||
webhook_by_events,
|
||||
events,
|
||||
qrcode,
|
||||
token,
|
||||
@@ -60,7 +61,12 @@ export class InstanceController {
|
||||
|
||||
if (webhook) {
|
||||
try {
|
||||
this.webhookService.create(instance, { enabled: true, url: webhook, events });
|
||||
this.webhookService.create(instance, {
|
||||
enabled: true,
|
||||
url: webhook,
|
||||
events,
|
||||
webhook_by_events,
|
||||
});
|
||||
|
||||
getEvents = (await this.webhookService.find(instance)).events;
|
||||
} catch (error) {
|
||||
@@ -98,7 +104,12 @@ export class InstanceController {
|
||||
|
||||
if (webhook) {
|
||||
try {
|
||||
this.webhookService.create(instance, { enabled: true, url: webhook, events });
|
||||
this.webhookService.create(instance, {
|
||||
enabled: true,
|
||||
url: webhook,
|
||||
events,
|
||||
webhook_by_events,
|
||||
});
|
||||
|
||||
getEvents = (await this.webhookService.find(instance)).events;
|
||||
} catch (error) {
|
||||
@@ -121,6 +132,7 @@ export class InstanceController {
|
||||
},
|
||||
hash,
|
||||
webhook,
|
||||
webhook_by_events,
|
||||
events: getEvents,
|
||||
qrcode: getQrcode,
|
||||
};
|
||||
|
||||
@@ -27,6 +27,12 @@ export class GroupInvite {
|
||||
inviteCode: string;
|
||||
}
|
||||
|
||||
export class GroupSendInvite {
|
||||
groupJid: string;
|
||||
description: string;
|
||||
numbers: string[];
|
||||
}
|
||||
|
||||
export class GroupUpdateParticipantDto extends GroupJid {
|
||||
action: 'add' | 'remove' | 'promote' | 'demote';
|
||||
participants: string[];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export class InstanceDto {
|
||||
instanceName: string;
|
||||
webhook?: string;
|
||||
webhook_by_events?: boolean;
|
||||
events?: string[];
|
||||
qrcode?: boolean;
|
||||
token?: string;
|
||||
|
||||
@@ -2,4 +2,5 @@ export class WebhookDto {
|
||||
enabled?: boolean;
|
||||
url?: string;
|
||||
events?: string[];
|
||||
webhook_by_events?: boolean;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ export class WebhookRaw {
|
||||
url?: string;
|
||||
enabled?: boolean;
|
||||
events?: string[];
|
||||
webhook_by_events?: boolean;
|
||||
}
|
||||
|
||||
const webhookSchema = new Schema<WebhookRaw>({
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
updateGroupSubjectSchema,
|
||||
updateGroupDescriptionSchema,
|
||||
groupInviteSchema,
|
||||
groupSendInviteSchema,
|
||||
} from '../../validate/validate.schema';
|
||||
import { RouterBroker } from '../abstract/abstract.router';
|
||||
import {
|
||||
@@ -21,6 +22,7 @@ import {
|
||||
GroupUpdateParticipantDto,
|
||||
GroupUpdateSettingDto,
|
||||
GroupToggleEphemeralDto,
|
||||
GroupSendInvite,
|
||||
} from '../dto/group.dto';
|
||||
import { groupController } from '../whatsapp.module';
|
||||
import { HttpStatus } from './index.router';
|
||||
@@ -120,12 +122,12 @@ export class GroupRouter extends RouterBroker {
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
})
|
||||
.get(this.routerPath('acceptInvite'), ...guards, async (req, res) => {
|
||||
const response = await this.inviteCodeValidate<GroupInvite>({
|
||||
.post(this.routerPath('sendInvite'), ...guards, async (req, res) => {
|
||||
const response = await this.groupNoValidate<GroupSendInvite>({
|
||||
request: req,
|
||||
schema: groupInviteSchema,
|
||||
ClassRef: GroupInvite,
|
||||
execute: (instance, data) => groupController.acceptInvite(instance, data),
|
||||
schema: groupSendInviteSchema,
|
||||
ClassRef: GroupSendInvite,
|
||||
execute: (instance, data) => groupController.sendInvite(instance, data),
|
||||
});
|
||||
|
||||
res.status(HttpStatus.OK).json(response);
|
||||
|
||||
@@ -104,6 +104,7 @@ import {
|
||||
GroupToggleEphemeralDto,
|
||||
GroupSubjectDto,
|
||||
GroupDescriptionDto,
|
||||
GroupSendInvite,
|
||||
} from '../dto/group.dto';
|
||||
import { MessageUpQuery } from '../repository/messageUp.repository';
|
||||
import { useMultiFileAuthStateDb } from '../../utils/use-multi-file-auth-state-db';
|
||||
@@ -204,6 +205,7 @@ export class WAStartupService {
|
||||
this.localWebhook.url = data?.url;
|
||||
this.localWebhook.enabled = data?.enabled;
|
||||
this.localWebhook.events = data?.events;
|
||||
this.localWebhook.webhook_by_events = data?.webhook_by_events;
|
||||
}
|
||||
|
||||
public async setWebhook(data: WebhookRaw) {
|
||||
@@ -224,11 +226,9 @@ export class WAStartupService {
|
||||
|
||||
if (Array.isArray(webhookLocal) && webhookLocal.includes(we)) {
|
||||
if (local && instance.MODE !== 'container') {
|
||||
const { WEBHOOK_BY_EVENTS } = instance;
|
||||
|
||||
let baseURL;
|
||||
|
||||
if (WEBHOOK_BY_EVENTS) {
|
||||
if (this.localWebhook.webhook_by_events) {
|
||||
baseURL = `${this.localWebhook.url}/${transformedWe}`;
|
||||
} else {
|
||||
baseURL = this.localWebhook.url;
|
||||
@@ -484,7 +484,7 @@ export class WAStartupService {
|
||||
|
||||
const { version } = await fetchLatestBaileysVersion();
|
||||
const session = this.configService.get<ConfigSessionPhone>('CONFIG_SESSION_PHONE');
|
||||
const browser: WABrowserDescription = [session.CLIENT, 'Chrome', release()];
|
||||
const browser: WABrowserDescription = [session.CLIENT, session.NAME, release()];
|
||||
|
||||
const socketConfig: UserFacingSocketConfig = {
|
||||
auth: {
|
||||
@@ -1773,11 +1773,28 @@ export class WAStartupService {
|
||||
}
|
||||
}
|
||||
|
||||
public async acceptInvite(id: GroupInvite) {
|
||||
public async sendInvite(id: GroupSendInvite) {
|
||||
try {
|
||||
return await this.client.groupAcceptInvite(id.inviteCode);
|
||||
const inviteCode = await this.inviteCode({ groupJid: id.groupJid });
|
||||
const inviteUrl = inviteCode.inviteUrl;
|
||||
const numbers = id.numbers.map((number) => this.createJid(number));
|
||||
const description = id.description ?? '';
|
||||
|
||||
const msg = `${description}\n${inviteUrl}`;
|
||||
|
||||
const message = {
|
||||
linkPreview: {
|
||||
text: msg,
|
||||
},
|
||||
};
|
||||
|
||||
for await (const number of numbers) {
|
||||
await this.sendMessageWithTyping(number, message);
|
||||
}
|
||||
|
||||
return { send: true, inviteUrl };
|
||||
} catch (error) {
|
||||
throw new NotFoundException('No invite info', id.inviteCode);
|
||||
throw new NotFoundException('No send invite');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1831,7 +1848,7 @@ export class WAStartupService {
|
||||
update.groupJid,
|
||||
update.expiration,
|
||||
);
|
||||
return { toggleEphemeral: toggleEphemeral };
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
throw new BadRequestException('Error updating setting', error.toString());
|
||||
}
|
||||
|
||||
@@ -34,7 +34,12 @@ export declare namespace wa {
|
||||
profilePictureUrl?: string;
|
||||
};
|
||||
|
||||
export type LocalWebHook = { enabled?: boolean; url?: string; events?: string[] };
|
||||
export type LocalWebHook = {
|
||||
enabled?: boolean;
|
||||
url?: string;
|
||||
events?: string[];
|
||||
webhook_by_events?: boolean;
|
||||
};
|
||||
|
||||
export type StateConnection = {
|
||||
instance?: string;
|
||||
|
||||
Reference in New Issue
Block a user