Authentication Overview
Evolution API uses API key authentication to secure all endpoints. There are two types of authentication:
Global API Key - Full access to all instances and administrative operations
Instance Token - Restricted access to a specific instance only
All API requests require an apikey header with either a global key or instance-specific token.
API keys are passed via the apikey HTTP header (not Authorization). This allows you to use standard authentication schemes like JWT for your own application layer.
Global API Key
The global API key grants full administrative access to your Evolution API installation.
Setting the Global Key
Configure in your .env file:
# Define a global apikey to access all instances.
AUTHENTICATION_API_KEY = 429683C4C977415CAAFCCE10F7D57E11
Generate a strong, random API key for production. Use at least 32 characters with mixed alphanumeric characters. Never use the example key above.
Generate a Secure Key
Linux/Mac
Node.js
Python
PowerShell
# Generate a secure random key
openssl rand -hex 32
Global Key Capabilities
With the global API key, you can:
Create new instances
Delete any instance
Fetch information about all instances
Access any instance’s endpoints
Modify system-wide configurations
# Create instance with global key
curl -X POST https://your-api.com/instance/create \
-H "apikey: 429683C4C977415CAAFCCE10F7D57E11" \
-H "Content-Type: application/json" \
-d '{"instanceName": "new-instance"}'
# Fetch all instances
curl -X GET https://your-api.com/instance/fetchInstances \
-H "apikey: 429683C4C977415CAAFCCE10F7D57E11"
Instance Tokens
Each instance has its own unique authentication token, providing scoped access to that instance only.
How Instance Tokens Work
When you create an instance, Evolution API generates a unique token:
{
"instance" : {
"instanceName" : "my-whatsapp" ,
"instanceId" : "550e8400-e29b-41d4-a716-446655440000"
},
"hash" : "B5F6E890D1234567890ABCDEF1234567" // This is the instance token
}
Custom Instance Tokens
You can specify a custom token during instance creation:
{
"instanceName" : "my-whatsapp" ,
"token" : "my-custom-secure-token-here" ,
"qrcode" : true
}
Custom tokens must be unique across all instances. The API will reject duplicate tokens.
From the source code (src/api/services/auth.service.ts:7):
public async checkDuplicateToken ( token : string ) {
if ( ! token ) {
return true ;
}
const instances = await this . prismaRepository . instance . findMany ({
where: { token },
});
if ( instances . length > 0 ) {
throw new BadRequestException ( 'Token already exists' );
}
return true ;
}
Using Instance Tokens
Instance tokens restrict API access to only that instance:
# Send message with instance token
curl -X POST https://your-api.com/message/sendText/my-whatsapp \
-H "apikey: B5F6E890D1234567890ABCDEF1234567" \
-H "Content-Type: application/json" \
-d '{
"number": "5511999999999",
"text": "Hello from Evolution API!"
}'
# Check connection state
curl -X GET https://your-api.com/instance/connectionState/my-whatsapp \
-H "apikey: B5F6E890D1234567890ABCDEF1234567"
Attempting to access a different instance with this token will fail:
# This will return 401 Unauthorized
curl -X GET https://your-api.com/instance/connectionState/different-instance \
-H "apikey: B5F6E890D1234567890ABCDEF1234567"
Authentication Flow
Here’s how Evolution API validates requests:
Extract API Key
The API extracts the apikey header from your request: // From src/api/guards/auth.guard.ts:12
const key = req . get ( 'apikey' );
if ( ! key ) {
throw new UnauthorizedException ();
}
Check Global Key
First, check if the key matches the global API key: // From src/api/guards/auth.guard.ts:19
if ( env . KEY === key ) {
return next (); // Global access granted
}
Check Instance Token
If not a global key, verify it’s a valid instance token: // From src/api/guards/auth.guard.ts:29
const instance = await prismaRepository . instance . findUnique ({
where: { name: param . instanceName },
});
if ( instance . token === key ) {
return next (); // Instance access granted
}
Reject Invalid Keys
If neither match, reject the request: throw new UnauthorizedException ();
Security Best Practices
Always use HTTPS to encrypt API keys in transit: # ✅ Good - Encrypted connection
https://your-api.com/instance/create
# ❌ Bad - Exposes API key in plain text
http://your-api.com/instance/create
Configure SSL in your .env: SERVER_TYPE = https
SSL_CONF_PRIVKEY = /path/to/private.key
SSL_CONF_FULLCHAIN = /path/to/fullchain.crt
Implement a key rotation policy:
Generate a new global API key
Update your .env file
Restart Evolution API
Update all client applications
For instance tokens, delete and recreate instances with new tokens: # Delete old instance
curl -X DELETE https://your-api.com/instance/delete/my-instance \
-H "apikey: OLD_TOKEN"
# Create with new token
curl -X POST https://your-api.com/instance/create \
-H "apikey: GLOBAL_KEY" \
-d '{"instanceName": "my-instance", "token": "NEW_TOKEN"}'
Never hardcode API keys in your application: // ❌ Bad - Hardcoded key
const apiKey = 'B5F6E890D1234567890ABCDEF1234567' ;
// ✅ Good - Environment variable
const apiKey = process . env . EVOLUTION_API_KEY ;
// ✅ Good - Secrets manager
const apiKey = await secretsManager . getSecret ( 'evolution-api-key' );
Use environment variables, secret managers, or encrypted configuration files.
For customer-facing applications, always use instance tokens instead of the global key: // Multi-tenant SaaS example
class WhatsAppService {
async sendMessage ( customerId , message ) {
// Each customer gets their own instance token
const instanceToken = await db . getInstanceToken ( customerId );
return fetch ( ` ${ EVOLUTION_API } /message/sendText/ ${ customerId } ` , {
method: 'POST' ,
headers: {
'apikey' : instanceToken , // Not the global key!
'Content-Type' : 'application/json'
},
body: JSON . stringify ( message )
});
}
}
Monitor Authentication Failures
Track failed authentication attempts: // Monitor 401 responses
const response = await fetch ( endpoint , { headers });
if ( response . status === 401 ) {
// Log and alert on authentication failures
logger . error ( 'Authentication failed' , {
endpoint ,
timestamp: new Date ()
});
// Implement rate limiting
await rateLimit . increment ( ip );
}
Implement IP Whitelisting
Restrict API access by IP address at the network level: # Nginx configuration
location /instance/create {
allow 203.0.113.0/24; # Your office network
deny all ;
proxy_pass http://evolution-api:8080;
}
Or use a firewall/VPC to limit access to your Evolution API server.
Authentication in Different Languages
JavaScript/Node.js
Python
PHP
Go
const EVOLUTION_API = 'https://your-api.com' ;
const GLOBAL_API_KEY = process . env . EVOLUTION_GLOBAL_KEY ;
const INSTANCE_TOKEN = process . env . EVOLUTION_INSTANCE_TOKEN ;
// Using global key to create instance
async function createInstance ( name ) {
const response = await fetch ( ` ${ EVOLUTION_API } /instance/create` , {
method: 'POST' ,
headers: {
'apikey' : GLOBAL_API_KEY ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({ instanceName: name })
});
if ( ! response . ok ) {
throw new Error ( `Authentication failed: ${ response . status } ` );
}
return response . json ();
}
// Using instance token to send message
async function sendMessage ( instanceName , number , text ) {
const response = await fetch (
` ${ EVOLUTION_API } /message/sendText/ ${ instanceName } ` ,
{
method: 'POST' ,
headers: {
'apikey' : INSTANCE_TOKEN ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({ number , text })
}
);
return response . json ();
}
Expose Instances Configuration
Control which instances are visible in fetch requests:
# In .env
AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES = true
true - All instances are returned in fetch requests
false - Instances are hidden, only explicitly requested instances are returned
This adds privacy for multi-tenant deployments where customers shouldn’t see other instances.
Common Authentication Errors
401 Unauthorized - Missing API Key
{
"statusCode" : 401 ,
"message" : "Unauthorized" ,
"error" : "Unauthorized"
}
Cause : No apikey header providedSolution : Add the header to your request:curl -H "apikey: YOUR_API_KEY" ...
401 Unauthorized - Invalid API Key
Cause : Wrong API key or tokenSolution : Verify you’re using the correct key:
Check .env file for global key
Confirm instance token from creation response
Ensure no extra spaces or newlines in the key
403 Forbidden - Wrong Instance Token
{
"statusCode" : 403 ,
"message" : "Forbidden" ,
"error" : "Forbidden"
}
Cause : Using instance token for a different instanceSolution : Use the correct token for each instance or use the global API key
400 Bad Request - Duplicate Token
{
"statusCode" : 400 ,
"message" : "Token already exists"
}
Cause : Trying to create instance with a token that’s already in useSolution : Choose a unique token or let Evolution API generate one automatically
Next Steps
Instances Learn how to create and manage instances
Webhooks Configure webhooks for real-time event notifications
Multi-Tenant Build secure multi-tenant applications
API Reference Explore all available API endpoints