API documentation
OpenAPI spec →Build scam detection into your app. 450+ signals, 50ms scoring, 99.5% uptime.
Try it live
Authentication
Include your API key in the x-api-key header. The free tier (100 req/month) works without a key for testing.
curl https://suss-api-353192091596.us-central1.run.app/api/score \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"text": "Is this a scam?"}'Endpoints
/api/scoreScore text for scam probability with full intelligence (signals, guidance, company/domain reputation)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| text | string | required | Message text to analyze (max 10,000 chars) |
| url | string | optional | URL for domain reputation analysis |
| channel | string | optional | Scoring channel: sms, email, marketplace, social, chat (adjusts thresholds) |
| image_url | string | optional | Image URL for OCR + visual intelligence |
| title | string | optional | Listing/email title (scored alongside text) |
| profile | string | optional | Protection profile: relaxed, balanced, maximum, family, seller |
| conversation_context | object | optional | Multi-turn context for DM/chat scoring |
Request
{
"text": "Congratulations! You've won a $1000 gift card. Click here to claim: bit.ly/free-prize",
"url": "https://example.com/listing",
"channel": "marketplace"
}Response
{
"score": 0.92,
"bucket": "HIGH",
"reasons": [
"lottery_prize_scam",
"urgency_language",
"suspicious_url"
],
"category": "consumer_fraud",
"ml_prob": 0.89,
"confidence": "high",
"detected_language": "en",
"guidance": {
"primary_concern": "This is a prize/lottery scam",
"main_action": "Do not click any links or provide personal information"
},
"contextual_guidance": {
"what": "Someone is trying to lure you with a fake prize",
"so_what": "Prize scams collected $301M from victims in 2024 (FTC data)",
"now_what": [
"Do not click the link",
"Block the sender",
"Report to FTC at reportfraud.ftc.gov"
],
"verdict_summary": "This is very likely a scam — you cannot win a lottery you did not enter"
},
"embedding_signals": {
"risk_signals": [
"lottery_prize_scam",
"urgency_language"
],
"legitimacy_signals": []
}
}/api/score/batchScore up to 25 items in one request. Returns array of results.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| items | array | required | Array of objects, each with text (required) + optional url, channel, title |
Request
{
"items": [
{
"text": "Hey, I'm selling a PS5 for $100. Venmo only."
},
{
"text": "Your package is ready for pickup at the post office."
}
]
}Response
{
"results": [
{
"score": 0.78,
"bucket": "HIGH",
"reasons": [
"too_good_to_be_true",
"unprotected_payment"
]
},
{
"score": 0.08,
"bucket": "LOW",
"reasons": []
}
]
}/api/domain/quick/{domain}Quick domain trust check — WHOIS age, registrar, Tranco rank, risk signals
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| domain | path | required | Domain name to check (e.g., example.com) |
Response
{
"domain": "sketchy-deals.xyz",
"age_days": 5,
"registrar": "NameCheap",
"risk_level": "high",
"tranco_rank": null,
"signals": [
"new_domain",
"privacy_protected",
"suspicious_tld"
]
}/feedbackSubmit user feedback on a score result (thumbs up/down). Feeds active learning pipeline.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| submission_id | string | required | The submission ID from a /score response |
| vote | string | required | "up" (correct) or "down" (incorrect) |
| reason | string | optional | Feedback reason: false_positive, false_negative, wrong_category |
| notes | string | optional | Free-text notes |
Request
{
"submission_id": "abc-123-def",
"vote": "down",
"reason": "false_positive",
"notes": "This was a legitimate newsletter"
}Response
{
"status": "ok",
"message": "Feedback recorded"
}/ocrUpload an image for OCR text extraction + scam scoring. Supports JPEG, PNG, WebP.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| file | file | required | Image file (multipart/form-data) |
Request
multipart/form-data with 'file' field (image/jpeg, image/png, image/webp, max 10MB)
Response
{
"text": "URGENT: Your account has been compromised. Call 1-800-SCAM-NOW",
"score": 0.85,
"bucket": "HIGH",
"signals": [
"tech_support_callback_scam",
"urgency_language"
]
}Channel-aware scoring
Pass a channel field for optimized detection thresholds. Each channel adjusts sensitivity for its context.
| Channel | Threshold | Use case |
|---|---|---|
sms | 0.25 | Short messages, high scam prevalence |
email | 0.35 | Email with more context |
marketplace | 0.40 | Listings mixed with legit commerce |
social | 0.30 | Social media DMs |
chat | 0.30 | Real-time messaging (WhatsApp, Messenger) |
checkout | 0.40 | Checkout/payment pages |
Webhooks
Register a webhook URL to receive real-time notifications instead of polling. All webhooks are signed with HMAC-SHA256 for authenticity verification.
Events
| Event | Description |
|---|---|
enrichment.complete | Full analysis complete (image, domain, company intelligence) |
score.high_risk | A HIGH-risk score was detected |
visual_match.found | Known scam image matched via pHash |
feedback.received | User submitted feedback on a score |
Payload example
{
"event": "score.high_risk",
"timestamp": "2026-02-21T12:00:00Z",
"data": {
"submission_id": "abc-123",
"score": 0.92,
"bucket": "HIGH",
"signals": [
"ceo_urgent_wire",
"wire_transfer_pressure"
],
"category": "enterprise_fraud"
}
}Verifying signatures
import hmac, hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), payload, hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)Pricing tiers
Error codes
| Status | Meaning | Resolution |
|---|---|---|
200 | Success | - |
400 | Bad request | Check request body format |
401 | Unauthorized | Check your API key |
429 | Rate limited | Wait and retry, or upgrade tier |
500 | Server error | Retry with exponential backoff |