Spaces:
Sleeping
Staff WhatsApp OTP Integration - Complete Guide
Overview
Staff authentication now uses WATI WhatsApp API to send OTP codes via WhatsApp messages, providing a secure and convenient login method for staff/employee users.
Date: February 5, 2026
Integration: WATI WhatsApp Business API
Authentication Type: Mobile OTP via WhatsApp
Features
Staff OTP Authentication
- β WhatsApp OTP delivery via WATI API
- β Random 6-digit OTP generation
- β 5-minute OTP expiration
- β Maximum 3 verification attempts
- β One-time use enforcement
- β Staff role validation (excludes admin users)
- β Active user status verification
- β Message delivery tracking
Security Features
- β
Separate OTP collection for staff (
staff_otps) - β User existence verification before sending OTP
- β Role-based access control (staff only, not admin)
- β Account status validation
- β JWT token generation with merchant context
- β Comprehensive audit logging
Architecture
Components
StaffAuthService (
app/auth/services/staff_auth_service.py)- Orchestrates staff OTP flow
- Validates staff user eligibility
- Integrates with WatiService
- Manages OTP storage and verification
WatiService (
app/auth/services/wati_service.py)- Handles WATI API communication
- Supports multiple templates (customer & staff)
- Tracks message delivery
Staff Router (
app/auth/controllers/staff_router.py)/staff/send-otp- Send OTP endpoint/staff/login/mobile-otp- Verify OTP and login
Configuration (
app/core/config.py)WATI_STAFF_OTP_TEMPLATE_NAME- Staff template name
Setup Instructions
1. Create Staff WhatsApp Template in WATI
Template Name: staff_otp_login
Template Content:
Your staff login OTP is: {{otp_code}}
This code will expire in {{expiry_time}} minutes.
Do not share this code with anyone.
Required Elements:
- Category: AUTHENTICATION
- OTP placeholder:
{{otp_code}} - Expiry time placeholder:
{{expiry_time}} - Security disclaimer
- Button: "Copy Code" or "One-Tap Autofill"
Submit for WhatsApp approval (24-48 hours)
2. Environment Configuration
Already configured in .env:
WATI_API_ENDPOINT=https://live-mt-server.wati.io/104318
WATI_ACCESS_TOKEN=eyJhbGci...
WATI_STAFF_OTP_TEMPLATE_NAME=staff_otp_login
3. Database Collection
A new MongoDB collection staff_otps is automatically created with the following schema:
{
phone: "+919999999999", // Normalized phone number
user_id: "uuid", // Staff user ID
username: "staff@example.com", // Staff username
otp: "123456", // 6-digit code
created_at: ISODate("..."), // Creation timestamp
expires_at: ISODate("..."), // Expiration (5 min)
attempts: 0, // Verification attempts
verified: false, // Verification status
wati_message_id: "abc-123-..." // WATI tracking ID
}
API Endpoints
POST /staff/send-otp
Send OTP to staff mobile number via WhatsApp.
Request:
{
"phone": "+919999999999"
}
Response (Success):
{
"success": true,
"message": "OTP sent successfully via WhatsApp",
"expires_in": 300
}
Response (Error - User Not Found):
{
"detail": "Staff user not found for this phone number"
}
Status: 404
Response (Error - Admin User):
{
"detail": "Admin login not allowed via staff OTP"
}
Status: 403
Response (Error - Inactive User):
{
"detail": "User account is inactive"
}
Status: 403
POST /staff/login/mobile-otp
Verify OTP and authenticate staff user.
Request:
{
"phone": "+919999999999",
"otp": "123456"
}
Response (Success):
{
"access_token": "eyJhbGci...",
"token_type": "bearer",
"expires_in": 28800,
"user_info": {
"user_id": "uuid",
"username": "staff@example.com",
"email": "staff@example.com",
"full_name": "Staff Name",
"role": "staff",
"merchant_id": "merchant-uuid",
"merchant_type": "retail",
"phone": "+919999999999",
"status": "active",
"permissions": []
}
}
Response (Error - Invalid OTP):
{
"detail": "Invalid OTP"
}
Status: 401
Response (Error - Expired OTP):
{
"detail": "OTP has expired"
}
Status: 401
Response (Error - Too Many Attempts):
{
"detail": "Too many attempts. Please request a new OTP"
}
Status: 401
Authentication Flow
Send OTP Flow
1. Staff requests OTP β POST /staff/send-otp
β
2. Verify staff user exists with phone number
β
3. Validate user is staff role (not admin)
β
4. Check user status is active
β
5. Generate random 6-digit OTP
β
6. Send OTP via WATI WhatsApp API
β
7. Store OTP in staff_otps collection
β
8. Return success response
Verify OTP Flow
1. Staff submits OTP β POST /staff/login/mobile-otp
β
2. Retrieve OTP from staff_otps collection
β
3. Validate OTP (expiry, attempts, correctness)
β
4. Verify user is still active and staff role
β
5. Update last login timestamp
β
6. Generate JWT token with merchant context
β
7. Return authentication response
Differences from Customer OTP
| Feature | Customer OTP | Staff OTP |
|---|---|---|
| Collection | customer_otps |
staff_otps |
| Template | cust_otp |
staff_otp_login |
| User Validation | Find or create customer | Must exist as staff user |
| Role Check | N/A | Must be staff (not admin) |
| Status Check | N/A | Must be active |
| Endpoints | /customer/auth/* |
/staff/* |
| User Creation | Auto-creates new customers | No auto-creation |
Testing
Quick Test
cd cuatrolabs-auth-ms
python test_staff_wati_otp.py
Test Options:
- Full staff OTP flow (send + verify)
- Direct WATI service test
- API endpoints test
Manual API Testing
# Send OTP to staff
curl -X POST http://localhost:8001/staff/send-otp \
-H "Content-Type: application/json" \
-d '{"phone": "+919999999999"}'
# Verify OTP and login
curl -X POST http://localhost:8001/staff/login/mobile-otp \
-H "Content-Type: application/json" \
-d '{"phone": "+919999999999", "otp": "123456"}'
Prerequisites for Testing
- Staff user must exist in
system_userscollection - User must have phone number set
- User role must be staff/employee (not admin)
- User status must be "active"
- Phone number must be WhatsApp-enabled
Security Considerations
Staff-Specific Security
- User Existence: OTP only sent to existing staff users
- Role Validation: Admins cannot use staff OTP login
- Status Check: Only active users can receive OTP
- Separate Storage: Staff OTPs stored separately from customer OTPs
- Audit Trail: All attempts logged with user context
General Security
- Random OTP: Cryptographically secure random generation
- Expiration: 5-minute timeout
- Attempt Limiting: Maximum 3 attempts
- One-Time Use: OTPs marked as verified after use
- Secure Delivery: WhatsApp end-to-end encryption
- Message Tracking: WATI message IDs for audit
Error Handling
Common Errors
| Error | Cause | Solution |
|---|---|---|
| Staff user not found | Phone not in system_users | Add staff user with phone |
| Admin login not allowed | User has admin role | Use regular admin login |
| User account is inactive | Status not "active" | Activate user account |
| Invalid OTP | Wrong code entered | Request new OTP |
| OTP has expired | >5 minutes passed | Request new OTP |
| Too many attempts | >3 failed attempts | Request new OTP |
Troubleshooting
OTP Not Received
- Verify staff user exists: Check
system_userscollection - Verify phone number is correct
- Check user role is staff (not admin)
- Verify user status is active
- Check WATI template is approved
- Review application logs
- Verify staff user exists: Check
Verification Fails
- Check OTP not expired (5 minutes)
- Verify attempts not exceeded (max 3)
- Confirm OTP not already used
- Check phone number format
Logging
Log Levels
INFO:
Staff OTP sent successfully via WATI to +919999999999 for user staff@example.com
Staff OTP verified successfully for +919999999999, user: staff@example.com
Staff user logged in via mobile OTP: staff@example.com
WARNING:
Staff OTP request for non-existent phone: +919999999999
Admin user admin@example.com attempted staff OTP login
Inactive staff user attempted OTP: staff@example.com, status: inactive
Staff OTP verification failed - incorrect OTP for +919999999999
ERROR:
Failed to send staff OTP via WATI to +919999999999: Invalid WhatsApp number
Error sending staff OTP to +919999999999: [error details]
Monitoring
Metrics to Track
- Staff OTP send success rate
- Staff OTP verification success rate
- Failed login attempts by reason
- Average OTP delivery time
- WATI API response times
- Admin users attempting staff login
Alerts
- Staff OTP send failure rate >5%
- High number of invalid OTP attempts
- Admin users using staff endpoints
- WATI API errors
Deployment Checklist
- Code implementation complete
- Configuration added to .env
- Test script created
- Documentation created
- WATI staff template created
- WATI staff template approved
- Test with real staff users
- Production deployment
- Monitoring setup
Next Steps
Create WATI Template
- Log into WATI dashboard
- Create authentication template:
staff_otp_login - Submit for WhatsApp approval
Test with Staff Users
- Run
python test_staff_wati_otp.py - Test with multiple staff accounts
- Verify error scenarios
- Run
Deploy to Production
- Ensure template is approved
- Deploy updated code
- Monitor logs
- Track success rates
Support
Resources
- Test Script:
test_staff_wati_otp.py - Customer OTP Guide:
WATI_WHATSAPP_OTP_INTEGRATION.md - WATI API Docs: https://docs.wati.io
- WATI Support: https://support.wati.io
Troubleshooting
- Check logs:
cuatrolabs-auth-ms/logs/ - Run test script:
python test_staff_wati_otp.py - Verify staff user exists and is active
- Check WATI dashboard for message status
Status: β READY FOR TESTING
Next Step: Create and approve WATI staff authentication template.