Default Configuration
| Setting | Default | Description |
|---|---|---|
| Host | 127.0.0.1 | Network interface to bind to |
| Port | 8080 | TCP port to listen on |
| Notify URL | http://127.0.0.1:8899 | Main qai web server for hit notifications |
~/.qai/) is created automatically on first run.
CLI Configuration
All server settings are configured via CLI flags onqai ipi listen:
| Option | Type | Default | Description |
|---|---|---|---|
--host, -h | TEXT | 127.0.0.1 | Loopback interface only (127.0.0.1, localhost, ::1) |
--port, -p | INT | 8080 | TCP port to listen on |
--notify-url | TEXT | http://127.0.0.1:8899 | Where to send internal hit notifications |
Callback URL Structure
The listener accepts callbacks at two URL patterns:| Path | Token Validated | Description |
|---|---|---|
/c/<uuid>/<token> | Yes | Authenticated callback — token checked against database |
/c/<uuid> | No | Unauthenticated callback — recorded with token_valid=False |
Per-Campaign Authentication
Cryptographic tokens are generated automatically when payloads are created. No separate authentication configuration is needed. The token is embedded in the callback URL during payload generation:Confidence Scoring
Confidence is assigned automatically based on token validity and User-Agent analysis:| Level | Criteria |
|---|---|
| HIGH | Valid campaign token present |
| MEDIUM | No/invalid token + programmatic User-Agent |
| LOW | No/invalid token + browser/scanner User-Agent |
python-requests, httpx, aiohttp, urllib, curl, wget, node-fetch, axios, got, undici, fetch, llm, openai, langchain.
Bridge Token
The IPI listener runs as a separate process from the main qai web server. When a hit arrives, the listener notifies the web server via an internal HTTP POST so the web UI can update in real time via WebSocket. This internal communication is authenticated with a shared bridge token:- Location:
~/.qai/bridge.token - Format: 32 hex characters, generated via
secrets.token_hex(16) - File permissions:
0600on POSIX - Auto-generated: On first access by either process (race-safe exclusive file creation)
Authorization header of its internal POST. If the tokens don’t match (stale file), the notification is rejected — the hit is still recorded in the database but won’t appear in the web UI until the page is refreshed.
Health Check
The server exposes a health endpoint at/health that returns {"status": "ok"}.
Public exposure and tunnel mode
When the listener runs with--tunnel cloudflare (see Remote callbacks via Cloudflare Tunnel), a few behaviors differ from a bare loopback listener.
Forwarded-header trust. In tunnel mode the server resolves each hit’s source_ip from the CF-Connecting-IP header rather than the TCP peer. This trust is scoped to tunnel mode only — a bare loopback listener does not trust forwarded headers.
Hardening in tunnel mode. Tunneled listeners activate defensive measures against public-internet exposure: request body size limits, per-peer rate limiting, and a startup warning banner. These are defaults for tunnel mode and cannot be silently disabled.
State file permissions. The ~/.qai/active-callback state file is created with mode 0o600 on POSIX (owner read/write only). Windows has no direct equivalent; on Windows the file is protected only by the default user profile ACL. This is best-effort and is called out here as an explicit known limitation, not a hardening claim.
Network Considerations
For testing against cloud-hosted AI targets, keep the listener on loopback and expose it via tunnel:- Local testing:
http://127.0.0.1:8080when the agent runs on the same machine - Cloud targets:
qai ipi listen --tunnel cloudflareand use the printed HTTPS URL as--callback