Overview
Starting with version 8.0, GOWA supports managing multiple WhatsApp accounts simultaneously in a single server instance. Device scoping allows you to direct API operations to specific WhatsApp devices.
Device Identification
Each WhatsApp connection (device) is identified by a unique device ID . This ID can be:
Custom : Provided by you when creating a device (e.g., "my-primary-device", "support-team")
Auto-generated : A UUID assigned by the server if not specified
JID-based : The WhatsApp JID (e.g., "[email protected] ") after login
Specifying the Device
All device-scoped REST endpoints accept the device ID in two ways:
Pass the device ID in the X-Device-Id header:
curl -X GET http://localhost:3000/app/status \
-H "X-Device-Id: my-primary-device"
This method is preferred because:
Works with all HTTP methods (GET, POST, DELETE)
Keeps URLs clean
Easier to implement in client libraries
2. device_id Query Parameter
Alternatively, use the device_id query parameter:
curl -X GET "http://localhost:3000/app/status?device_id=my-primary-device"
If both the header and query parameter are provided, the header takes precedence .
URL Encoding for Special Characters
If your device ID contains special characters (like @), URL-encode it:
# Device ID: [email protected]
# URL-encoded: 6289685028129%40s.whatsapp.net
curl -X GET "http://localhost:3000/app/status?device_id=6289685028129%40s.whatsapp.net"
The header value is automatically decoded by the middleware.
Default Device Behavior
When only one device is registered, it becomes the default device:
# No device ID needed - uses the only registered device
curl -X GET http://localhost:3000/app/status
This makes single-device deployments backward-compatible with version 7.x.
Multi-Device Scenarios
When Multiple Devices Are Registered
If two or more devices are registered, you must specify the device ID:
# ❌ Error: device_id is required
curl -X GET http://localhost:3000/app/status
# ✅ Correct: specify device ID
curl -X GET http://localhost:3000/app/status \
-H "X-Device-Id: primary-device"
Response when device ID is missing:
{
"status" : 400 ,
"code" : "DEVICE_ID_REQUIRED" ,
"message" : "device_id is required via X-Device-Id header or device_id query" ,
"results" : null
}
When Device Not Found
If the specified device ID doesn’t exist:
curl -X GET http://localhost:3000/app/status \
-H "X-Device-Id: non-existent-device"
Response:
{
"status" : 404 ,
"code" : "DEVICE_NOT_FOUND" ,
"message" : "device not found; create a device first from /api/devices or provide a valid X-Device-Id" ,
"results" : {
"device_id" : "non-existent-device"
}
}
Device Management Endpoints
The /devices endpoints manage device lifecycle. These endpoints are not device-scoped (no X-Device-Id header needed).
List All Devices
Returns all registered devices with their connection status:
{
"status" : 200 ,
"code" : "SUCCESS" ,
"message" : "Devices retrieved" ,
"results" : {
"devices" : [
{
"id" : "primary-device" ,
"jid" : "[email protected] " ,
"is_connected" : true ,
"is_logged_in" : true
},
{
"id" : "support-device" ,
"jid" : null ,
"is_connected" : false ,
"is_logged_in" : false
}
]
}
}
Create a Device
POST /devices
Content-Type: application/json
{
"device_id" : "support-device"
}
The device_id field is optional. If omitted, a UUID will be generated:
{
"status" : 200 ,
"code" : "SUCCESS" ,
"message" : "Device created" ,
"results" : {
"device_id" : "support-device" ,
"message" : "Device slot created. Use /devices/{device_id}/login to connect."
}
}
Get Device Info
Example:
curl -X GET http://localhost:3000/devices/primary-device
Response:
{
"status" : 200 ,
"code" : "SUCCESS" ,
"message" : "Device info retrieved" ,
"results" : {
"id" : "primary-device" ,
"jid" : "[email protected] " ,
"is_connected" : true ,
"is_logged_in" : true ,
"push_name" : "John Doe"
}
}
Login a Device (QR Code)
GET /devices/{device_id}/login
Initiates QR code login:
curl -X GET http://localhost:3000/devices/primary-device/login
Login a Device (Pairing Code)
POST /devices/{device_id}/login/code?phone= 628912344551
Initiates pairing code login for the specified phone number:
curl -X POST "http://localhost:3000/devices/primary-device/login/code?phone=628912344551"
Logout a Device
POST /devices/{device_id}/logout
Logs out and removes the session:
curl -X POST http://localhost:3000/devices/primary-device/logout
Remove a Device
DELETE /devices/{device_id}
Removes a device from the server (does not logout from WhatsApp):
curl -X DELETE http://localhost:3000/devices/support-device
Legacy Endpoints (v7 Compatibility)
For backward compatibility, v7-style endpoints under /app are still available:
GET /app/login - Login with QR (requires X-Device-Id)
GET /app/login-with-code - Login with pairing code
GET /app/logout - Logout
GET /app/reconnect - Reconnect
GET /app/status - Get connection status
GET /app/devices - List devices
These endpoints require the X-Device-Id header when multiple devices are registered.
WebSocket Device Scoping
For WebSocket connections, specify the device ID as a query parameter:
const ws = new WebSocket ( 'ws://localhost:3000/ws?device_id=primary-device' );
ws . onmessage = ( event ) => {
const data = JSON . parse ( event . data );
console . log ( 'Event:' , data );
};
WebSocket events are scoped to the connected device. Each device requires a separate WebSocket connection.
Webhook Device Identification
All webhook events include a top-level device_id field identifying which device received the event:
This allows your webhook handler to route events to the appropriate device/account.
Middleware Implementation
The device scoping is implemented in device.go middleware:
func DeviceMiddleware ( dm * whatsapp . DeviceManager ) fiber . Handler {
return func ( c * fiber . Ctx ) error {
deviceID := strings . TrimSpace ( c . Get ( DeviceIDHeader ))
// URL-decode the header value
if decoded , err := url . QueryUnescape ( deviceID ); err == nil {
deviceID = decoded
}
if deviceID == "" {
deviceID = strings . TrimSpace ( c . Query ( "device_id" ))
}
instance , resolvedID , err := dm . ResolveDevice ( deviceID )
if err != nil {
// Return appropriate error response
}
c . Locals ( "device_id" , resolvedID )
c . Locals ( "device" , instance )
return c . Next ()
}
}
Best Practices
Use Descriptive Device IDs
Choose meaningful device IDs that reflect their purpose:
# ✅ Good
primary-device
support-team
customer-service-1
marketing-bot
# ❌ Avoid
device1
test
abc123
Device ID Naming Conventions
Use lowercase with hyphens: my-device-name
Avoid spaces and special characters
Keep it concise but descriptive
Use environment-based prefixes in multi-environment setups: prod-primary, staging-test
Single Device Deployments
If you only need one device, you can omit the device ID entirely:
# Create the only device
curl -X POST http://localhost:3000/devices \
-H "Content-Type: application/json" \
-d '{"device_id": "main"}'
# Login
curl -X GET http://localhost:3000/devices/main/login
# All subsequent requests work without X-Device-Id
curl -X GET http://localhost:3000/app/status
Multi-Device Use Cases
Department-based routing : sales-bot, support-bot, marketing-bot
Environment isolation : prod-primary, prod-backup, staging-test
Customer segmentation : vip-customers, general-customers
Regional distribution : us-east-device, eu-central-device, asia-device
Troubleshooting
”DEVICE_MANAGER_UNAVAILABLE” Error
If the device manager is not initialized:
{
"status" : 503 ,
"code" : "DEVICE_MANAGER_UNAVAILABLE" ,
"message" : "Device manager is not initialized" ,
"results" : null
}
Solution : Ensure the server is fully started before making requests.
Device ID Not Working After Login
After logging in with QR/pairing code, the device’s internal ID may change to the JID format. Always use the id field from /devices responses, not the JID.
Next Steps
Error Handling Learn about device-related errors
Endpoints Explore device-scoped endpoints