Savdhaan API Documentation
Integrate real-time scam detection into your app. Analyze text, images, and URLs against 6+ threat intelligence sources.
Quickstart
Get started with the Savdhaan API in 3 steps. Scan any suspicious text or image and get an evidence-based risk score.
Create an account
Sign up with email or Google. Free — no credit card required.
Get your API key
Go to your Profile and create an API key. Keys start with svd_ and are shown only once.
Make your first scan
Send a POST request with the suspicious content. You'll get a risk score, evidence, and recommended actions.
curl -X POST https://api.savdhaan.in/api/v1/scan \
-H "X-API-Key: svd_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"content": "Congratulations! You won Rs 50,000. Click http://prize.xyz to claim.",
"content_type": "text"
}'Free tier includes 10 scans/hour — enough to get started and test your integration.
Authentication
All API requests require an API key passed via the X-API-Key header.
X-API-Key: svd_4a7b3c2d9e1f5a6b8c0d3e4f5a6b7c8dKey details
- Format:
svd_prefix + 32 alphanumeric characters - Create keys at your Profile page (max 5 active keys)
- Keys are shown only once at creation — store them securely
- Never expose your API key in client-side code — always call from your server
POST /api/v1/scan
Scan text content for scam indicators. Returns a risk score, evidence, and recommended actions.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| content | string | Yes | Text to scan (1–10,000 characters) |
| content_type | enum | No | "text" (default) or "image" |
| channel | enum | No | "sms" | "whatsapp" | "email" | "social_dm" | "website" | "other" |
| category | enum | No | "scam_check" (default) | "job_offer" | "rental_lease" | "investment" | "contract" | "auto" |
| locale | string | No | Language hint, e.g. "en" (default), "hi" |
Example
curl -X POST https://api.savdhaan.in/api/v1/scan \
-H "X-API-Key: svd_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"content": "Congratulations! You won Rs 50,000. Click http://prize.xyz to claim.",
"content_type": "text"
}'Response
{
"ok": true,
"data": {
"scan_id": "e7b26d9c-5a2b-4e1a-8f3c-9d2e1c5b7a4f",
"risk_score": 92,
"risk_level": "critical",
"scam_type": "lottery_prize",
"explanation": "This message exhibits multiple lottery scam indicators...",
"evidence": [
{
"source": "Pattern Detection",
"detail": "Contains lottery/prize scam phrases",
"is_threat": true,
"confidence": 0.99
},
{
"source": "URL Reputation",
"detail": "Domain prize.xyz registered 3 days ago",
"is_threat": true,
"confidence": 0.95
}
],
"actions": [
"Do not click any links",
"Delete the message immediately",
"Report to your mobile provider"
],
"entities": {
"urls": ["http://prize.xyz"],
"phones": [],
"emails": [],
"crypto_addresses": [],
"upi_ids": []
},
"checks_performed": [
"entity_extraction",
"rule_based_pattern_detection",
"url_reputation (Google Safe Browsing, PhishTank, URLhaus, VirusTotal)",
"domain_age_verification (WHOIS)",
"llm_classification"
],
"checks_not_available": [],
"confidence_note": "High confidence based on multiple threat signals",
"content_snippet": "Congratulations! You won Rs 50,000...",
"scam_card": {
"card_id": "lty7x9k2",
"card_url": "https://savdhaan.in/card/lty7x9k2",
"image_url": "https://savdhaan.in/static/cards/lty7x9k2.png"
},
"community": {
"total_similar_reports": 42,
"entity_signals": [],
"first_reported_at": "2025-12-15T10:30:00Z"
},
"processing_time_ms": 2156,
"created_at": "2026-02-22T16:30:45Z"
}
}POST /api/v1/scan/image
Scan an image (screenshot) for scam indicators. OCR extracts text automatically, then runs the same analysis pipeline as text scans.
multipart/form-data — not JSON.Request Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| file | file | Yes | Image file: JPEG, PNG, WebP, or GIF (max 10 MB) |
| channel | enum | No | "sms" | "whatsapp" | "email" | "social_dm" | "website" | "other" |
| category | enum | No | "scam_check" (default) | "job_offer" | "rental_lease" | "investment" | "contract" | "auto" |
| locale | string | No | Language hint, default: "en" |
Example
curl -X POST https://api.savdhaan.in/api/v1/scan/image \
-H "X-API-Key: svd_your_key_here" \
-F "file=@screenshot.png" \
-F "channel=whatsapp"Response format is identical to POST /scan.
GET /api/v1/scan/{scan_id}
Retrieve a previous scan result by its ID. Only returns scans created with your API key.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| scan_id | UUID | Yes | The scan ID returned from POST /scan |
Example
curl https://api.savdhaan.in/api/v1/scan/550e8400-e29b-41d4-a716-446655440000 \
-H "X-API-Key: svd_your_key_here"POST /api/v1/scan/streamSSE
Stream scan progress as Server-Sent Events. Same request body as POST /scan. Emits real-time progress events as each pipeline step completes, then a final result event.
Pipeline Steps (9 total)
| # | Step | Description |
|---|---|---|
| 1 | dedup_check | Check if this content was already scanned |
| 2 | entity_extraction | Extract URLs, phones, emails, UPI IDs, crypto addresses |
| 3 | rule_engine | Run pattern-matching rules (14 signals) |
| 4 | threat_intel | Query 6+ threat databases in parallel |
| 5 | llm_classification | AI-powered scam classification |
| 6 | score_merge | Merge all evidence into final risk score |
| 7 | actions | Generate recommended actions |
| 8 | persist | Save results to database |
| 9 | scam_card | Generate shareable scam card (if risk >= 40) |
Event Types
event: progress— Emitted after each pipeline step{
"scan_step": "threat_intel",
"step_number": 4,
"total_steps": 9,
"message": "Checking threat intelligence databases...",
"elapsed_ms": 1200
}event: result— Final event with the full scan resultevent: error— Emitted if the scan failsExample
curl -N -X POST https://api.savdhaan.in/api/v1/scan/stream \
-H "X-API-Key: svd_your_key_here" \
-H "Content-Type: application/json" \
-d '{"content": "Your account is blocked. Call +91-9999999999 to verify.", "content_type": "text"}'POST /api/v1/report
Submit feedback on a scan result. Helps improve our detection accuracy.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| scan_id | UUID | Yes | ID of the scan to report on |
| feedback_type | enum | Yes | "confirmed_scam" | "false_positive" | "false_negative" | "helpful" | "not_helpful" |
| comment | string | No | Additional context (max 2,000 characters) |
| contact_email | string | No | Email for follow-up (max 255 characters) |
Example
curl -X POST https://api.savdhaan.in/api/v1/report \
-H "X-API-Key: svd_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"scan_id": "550e8400-e29b-41d4-a716-446655440000",
"feedback_type": "confirmed_scam",
"comment": "This was a real phishing attempt"
}'Response
{
"ok": true,
"data": {
"report_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scan_id": "550e8400-e29b-41d4-a716-446655440000",
"feedback_type": "confirmed_scam",
"status": "pending",
"message": "Thank you for your feedback. It helps us improve."
}
}Response Format
All API responses use a consistent envelope format.
Success
{
"ok": true,
"data": { ... },
"error": null,
"meta": {
"request_id": "550e8400-..."
}
}Error
{
"ok": false,
"data": null,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded."
},
"meta": {
"request_id": "550e8400-..."
}
}Risk Level Scale
| Level | Score Range | Meaning |
|---|---|---|
| critical | 80–100 | Almost certainly a scam — do not engage |
| high | 60–79 | Strong scam indicators detected |
| medium | 40–59 | Some suspicious patterns — proceed with caution |
| low | 20–39 | Minor signals — likely safe but verify |
| none | 0–19 | No scam indicators found |
Key Response Fields
| Parameter | Type | Required | Description |
|---|---|---|---|
| scan_id | UUID | Yes | Unique identifier for this scan |
| risk_score | integer | Yes | 0–100 risk score |
| risk_level | string | Yes | critical | high | medium | low | none |
| scam_type | string | No | Detected scam category (e.g. phishing, upi_fraud, lottery_prize) |
| explanation | string | Yes | AI-generated explanation of the risk assessment |
| evidence | array | Yes | List of specific threat signals found (source, detail, confidence) |
| actions | array | Yes | Recommended actions for the user |
| entities | object | Yes | Extracted entities: urls, phones, emails, crypto_addresses, upi_ids |
| scam_card | object | No | Shareable scam card (card_id, card_url, image_url) — generated when risk >= 40 |
| community | object | No | Community signals: total_similar_reports, entity_signals |
| processing_time_ms | integer | Yes | Total scan time in milliseconds |
Error Codes
When a request fails, the response includes an error object with a machine-readable code.
| HTTP | Code | Description | Recovery |
|---|---|---|---|
| 400 | INVALID_INPUT | Request validation failed | Check request body and fix errors |
| 401 | UNAUTHORIZED | Missing or invalid API key | Provide a valid X-API-Key header |
| 404 | NOT_FOUND | Scan or resource not found | Verify the ID is correct |
| 413 | PAYLOAD_TOO_LARGE | Image exceeds 10 MB | Reduce image size |
| 415 | UNSUPPORTED_MEDIA_TYPE | Image format not supported | Use JPEG, PNG, WebP, or GIF |
| 429 | RATE_LIMIT_EXCEEDED | Plan rate limit reached | Wait and retry, or upgrade plan |
| 500 | INTERNAL_ERROR | Unexpected server error | Retry with exponential backoff |
Example Error Response
{
"ok": false,
"data": null,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Limit: 10 requests per hour."
},
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}Rate Limits
Rate limits are enforced per API key using a sliding window.
| Plan | Scans / Hour | Price |
|---|---|---|
| Free | 10 | $0 |
| Premium | 100 | Coming soon |
When you hit the rate limit, the API returns 429 Too Many Requests.
The response includes a Retry-After header indicating how many seconds to wait before retrying.
Need higher limits? Contact us for enterprise plans with custom rate limits.