Errors
HTTP status codes
| Status | Meaning |
|---|---|
200 | Success |
201 | Created (domain, payment) |
204 | No content (logout, delete) |
400 | Bad request |
401 | Unauthorized |
402 | Payment required — domain weight exhausted |
403 | Forbidden |
404 | Not found |
409 | Conflict (e.g. email registered) |
429 | Rate limit (login attempts, email cooldown) |
500 | Internal server error |
503 | REST gateway busy (concurrency limit) |
Error response format
{ "error": "invalid credentials" }
Common errors
401 Unauthorized (Dashboard)
JWT expired. Refresh:{ "token": "..." }. Refresh token is in HTTP-only cookie.
404 on domain endpoint
Use the domain’s UUID (id from GET /api/domains), not the hostname:
Webhook not received
- Endpoint returns
2xxwithin 1 second - Endpoint is publicly reachable over HTTPS
- Webhook URL set via Dashboard or
PUT /api/domains/{id}/webhook - Domain has remaining weight (not
402) - Check server logs for incoming POST
Score always 0
- Legitimate clean session (residential IP, matching OS, STUN OK)
- VPN 2-of-3 not triggered (only 1 signal)
- Check CSP:
connect-src blob: *.shieldlabs.ai,cdn.jsdelivr.net - Verify snippet loads without console errors
Two webhooks for one check
Normal when WebRTC completes — firstPhase: "initial", then Phase: "update" with recalculated score. Handle both or prefer the update.