A production-ready Microsoft Teams bot that brings AI-powered legal research into Teams conversations via the Vaquill API.
Quick Links: Prerequisites | Getting Credentials | Setup | Deployment | Troubleshooting
- AI-powered legal Q&A via Vaquill API (standard and deep research modes)
- Multi-turn conversation with context (client-side chat history)
- Rich Adaptive Cards with source citations (case name, court, citation, PDF links)
- Rate limiting (per-user, per-channel, per-tenant) with Redis or in-memory
- Security controls: tenant/channel allowlists, user blocklists
- Slash commands:
/help,/clear,/status - Thread support with @mentions in channels
| Requirement | Free Tier | Purpose |
|---|---|---|
| Azure Account | Yes | Bot registration and hosting |
| Vaquill API Key | Trial | Legal AI API (vq_key_...) |
| Microsoft Teams Admin | - | Install bot in Teams |
| Python 3.10+ | Yes | Runtime |
| Redis (Optional) | Yes | Distributed rate limiting |
You need 3 credentials to run the bot.
- Go to Azure Portal
- Search for "Microsoft Entra ID" > "App registrations" > "+ New registration"
- Fill in:
Name: vaquill-teams-bot Supported account types: Single tenant (recommended) or Multi-tenant Redirect URI: Leave blank - Click "Register"
- Copy the Application (Client) ID — save as
TEAMS_APP_ID
- Left menu > "Certificates & secrets" > "Client secrets" tab
- Click "+ New client secret"
- Description:
Teams Bot Secret, Expires: 24 months - Click "Add"
- Immediately copy the Value — save as
TEAMS_APP_PASSWORD
Copy the Value, not the "Secret ID". You can only see it once.
- Azure Portal > "Create a resource" > "Azure Bot"
- Fill in:
- Bot handle:
vaquill-teams-bot - Pricing tier: F0 (Free)
- Microsoft App ID: Enter the ID from Step 1
- Bot handle:
- "Review + Create" > "Create"
- Go to your Azure Bot > "Channels" > "Microsoft Teams" icon > "Apply"
- Go to Vaquill Dashboard
- Generate an API key (starts with
vq_key_) - Save as
VAQUILL_API_KEY
git clone https://github.com/Vaquill-AI/integrations.git
cd integrations/ms-teams-bot
python3 -m venv venv
source venv/bin/activate # macOS/Linux
# OR: venv\Scripts\activate # Windows
pip install -r requirements.txtcp .env.example .env
nano .env # or any text editorRequired Configuration:
# Microsoft Teams (from Azure Portal)
TEAMS_APP_ID=12345678-1234-1234-1234-123456789abc
TEAMS_APP_PASSWORD=abc123~XYZ456.789def-GHI012_JKL345
TEAMS_APP_TYPE=MultiTenant
# Vaquill API
VAQUILL_API_KEY=vq_key_your_key_heresource venv/bin/activate
python3 app.pyExpected Output:
INFO - Vaquill client initialized
INFO - Rate limiter initialized
INFO - Bot initialization complete
* Running on http://0.0.0.0:3978
curl http://localhost:3978/healthRATE_LIMIT_PER_USER=20 # Messages per minute per user
RATE_LIMIT_PER_CHANNEL=100 # Messages per hour per channel
RATE_LIMIT_PER_TENANT=500 # Messages per hour per organizationALLOWED_TENANTS=tenant-id-1,tenant-id-2 # Restrict to specific orgs
ALLOWED_CHANNELS=channel-id-1,channel-id-2 # Restrict to specific channels
BLOCKED_USERS=user-id-1,user-id-2 # Block specific usersCONVERSATION_TIMEOUT=86400 # 24 hours (seconds)
MAX_CONTEXT_MESSAGES=10 # Messages to keep in chat history
ENABLE_THREADING=trueVAQUILL_API_URL=https://api.vaquill.ai/api/v1 # API base URL
VAQUILL_MODE=standard # standard or deep
VAQUILL_COUNTRY_CODE=IN # ISO country code (optional)
SHOW_SOURCES=true # Show case citationsMAX_MESSAGE_LENGTH=4000
REQUIRE_MENTION_IN_CHANNELS=true
ENABLE_ADAPTIVE_CARDS=true
RESPONSE_TIMEOUT=30
LOG_LEVEL=INFO
PORT=3978-
Start your bot:
source venv/bin/activate python3 app.py -
In another terminal, start ngrok:
ngrok http 3978
-
Copy the HTTPS URL from ngrok output and add
/api/messages:https://631af35e4e38.ngrok-free.app/api/messages -
Update Azure Bot messaging endpoint:
- Azure Portal > Your Bot > Configuration
- Paste the URL in Messaging endpoint
- Click "Apply"
Free ngrok URLs change on restart — you'll need to update Azure each time.
docker build -t vaquill-teams-bot .
docker run -d --name teams-bot -p 3978:3978 --env-file .env vaquill-teams-bot
docker logs -f teams-botaz webapp up \
--name vaquill-teams-bot \
--resource-group vaquill-rg \
--runtime "PYTHON:3.12" \
--sku B1
# Set env vars in Azure Portal > Web App > Configuration > Application settings
# Set messaging endpoint to: https://vaquill-teams-bot.azurewebsites.net/api/messagesRailway.app: Fork repo > railway.app > New project from GitHub > Add env vars > Deploy > Copy URL > Update Azure endpoint.
Render.com: Create Web Service > Connect GitHub > Set env vars > Deploy.
-
Create a
deployment/folder with:manifest.json— setbotIdto yourTEAMS_APP_IDcolor.png— 192x192px iconoutline.png— 32x32px icon
-
Create ZIP:
cd deployment zip -r vaquill-bot.zip manifest.json color.png outline.png
Direct Upload:
- Open Teams > Apps > Manage your apps > Upload an app
- Choose "Upload a custom app"
- Select
vaquill-bot.zip
Developer Portal (if you hit duplicate errors):
- Visit https://dev.teams.microsoft.com/apps
- Click "Import app" > Upload ZIP
- Click "Publish" > "Publish to org"
- Personal Chat: Send a direct message to the bot
- Channel:
@Vaquill Bot what is Section 302 IPC? - Commands: Try
/help
| Command | Description |
|---|---|
/help |
Show available commands |
/clear |
Clear conversation history |
/status |
Check rate limits and bot status |
Personal Chat:
You: What is the test for negligence under tort law?
Bot: [Adaptive Card with answer + source citations]
In Channels (requires @mention):
You: @Vaquill Bot compare murder and culpable homicide under IPC
Bot: [Detailed comparison with case law citations]
In Threads:
You: Tell me about Section 302 IPC
Bot: Section 302 deals with punishment for murder...
You: (reply in thread) How does that compare to Section 304?
Bot: (continues in thread with context) Section 304 covers...
app.py Flask entry point, Bot Framework adapter
bot.py VaquillTeamsBot (ActivityHandler)
vaquill_client.py Async Vaquill API client (POST /api/v1/ask)
conversation_manager.py Client-side chat history (Redis or in-memory)
rate_limiter.py Sliding-window rate limiter
adaptive_cards.py Adaptive Card templates for responses/sources
auth_handler.py Teams JWT / tenant validation
input_validator.py Input sanitization and injection detection
config.py Environment-based configuration
- Check messaging endpoint: Azure Portal > Bot > Configuration — must end with
/api/messages - Check bot is installed: Teams > Apps > Manage your apps
- Check logs:
docker logs teams-botor terminal output - Try personal chat first to isolate channel permission issues
- Verify
TEAMS_APP_IDmatches Azure Portal > Bot > Configuration - Regenerate client secret if expired (Azure > Certificates & secrets)
- Restart bot after updating credentials
Test the API directly:
curl -X POST https://api.vaquill.ai/api/v1/ask \
-H "Authorization: Bearer vq_key_your_key" \
-H "Content-Type: application/json" \
-d '{"question": "What is Section 302 IPC?"}'Common errors:
- 401: Invalid API key — check
VAQUILL_API_KEY - 402: Insufficient credits — top up at vaquill.ai/dashboard
- 429: Rate limited — wait and retry
Increase limits in .env:
RATE_LIMIT_PER_USER=30
RATE_LIMIT_PER_CHANNEL=200Or use Redis for distributed rate limiting:
REDIS_URL=redis://localhost:6379LOG_LEVEL=DEBUG- Never commit
.envor secrets - Enable tenant restrictions in production:
ALLOWED_TENANTS=your-tenant-id - Use Azure Key Vault for production credential management
- Rotate secrets every 3-6 months
- Always use HTTPS for the messaging endpoint
MIT