Skip to main content

POST /api/v1/forms/analyze

Analyze a form submission for spam, bots, and phishing using AI classification.

Request

POST https://app.trolleyshield.com/api/v1/forms/analyze
Authorization: Bearer tsk_your_api_key_here
Content-Type: application/json

Body

{
"form_data": {
"name": "John Doe",
"email": "john@example.com",
"phone": "555-123-4567",
"message": "I'd like a quote for a new roof"
},
"behavioral_score": 85,
"form_context": "Main contact form for service inquiries",
"site_url": "https://yoursite.com",
"form_id": "contact-form",
"ip_address": "203.0.113.50"
}
FieldTypeRequiredDescription
form_dataobjectYesKey-value pairs of submitted form fields
behavioral_scorenumberNoClient-side human-likeness score (0-100). Defaults to 50
form_contextstringNoDescription of this specific form's purpose
site_urlstringNoThe website URL the form is on
form_idstringNoUnique identifier for the form
ip_addressstringNoSubmitter's IP address. Falls back to X-Forwarded-For header if not provided
tip

You don't need to provide business_context in the request — it's automatically pulled from your account settings. Set it in Settings → General → Business Context in the dashboard.

Response

Success (200)

{
"intent": "legitimate",
"confidence": 95,
"reasoning": "Professional inquiry with specific service request and valid contact information.",
"action": "allow",
"ai_analysis": true,
"ip_reputation": {
"threat_level": "low",
"fraud_score": null,
"country": "US",
"is_vpn": false,
"is_tor": false,
"is_proxy": false
}
}
FieldTypeDescription
intentstring | nullAI classification result (see table below)
confidencenumber | nullConfidence score (0-100)
reasoningstring1-2 sentence explanation of the classification
actionstringRecommended action: allow, flag, or block
ai_analysisbooleanWhether AI analysis was performed (false on free tier)
ip_reputationobject | nullIP intelligence data (Growth+ tiers with IP tracking enabled)

Intent Values

IntentActionDescription
legitimateallowReal person with genuine inquiry
spamblockGeneric spam content
botblockAutomated/bot submission
phishingblockPhishing or social engineering attempt
irrelevantflagReal submission but not relevant to the business
suspiciousflagUncertain, needs human review

IP Reputation Object

Returned only for Growth and Agency tiers with IP tracking enabled.

FieldTypeDescription
threat_levelstringlow, medium, high, or critical
fraud_scorenullReserved for future use
countrystring | nullTwo-letter country code (ISO 3166-1)
is_vpnbooleanWhether the IP belongs to a VPN provider
is_torbooleanWhether the IP is a Tor exit node
is_proxybooleanWhether the IP is a public proxy

Error (401)

{
"error": "Invalid or revoked API key"
}

Error (403)

{
"error": "API access requires a paid plan",
"tier": "free"
}

Error (429)

{
"error": "Usage limit exceeded",
"limit": 500,
"tier": "free"
}

Error (400)

{
"error": "Invalid request",
"details": {
"fieldErrors": {
"form_data": ["Required"]
}
}
}

Example: Node.js

const response = await fetch('https://app.trolleyshield.com/api/v1/forms/analyze', {
method: 'POST',
headers: {
'Authorization': 'Bearer tsk_your_api_key_here',
'Content-Type': 'application/json',
},
body: JSON.stringify({
form_data: {
name: formData.name,
email: formData.email,
message: formData.message,
},
site_url: 'https://yoursite.com',
form_id: 'contact-form',
}),
});

const result = await response.json();

if (result.action === 'block') {
// Reject the submission
return { error: 'Your submission could not be processed.' };
} else if (result.action === 'flag') {
// Accept but mark for review
saveSubmission(formData, { flagged: true });
} else {
// Accept normally
saveSubmission(formData);
}

Example: Python

import requests

response = requests.post(
'https://app.trolleyshield.com/api/v1/forms/analyze',
headers={
'Authorization': 'Bearer tsk_your_api_key_here',
'Content-Type': 'application/json',
},
json={
'form_data': {
'name': 'John Doe',
'email': 'john@example.com',
'message': 'I need a quote for roof repair',
},
'site_url': 'https://yoursite.com',
'form_id': 'contact-form',
},
)

result = response.json()
print(f"Intent: {result['intent']}, Action: {result['action']}")

Failsafe Behavior

If the AI analysis fails internally, the API still returns a 200 with a safe default:

{
"intent": null,
"confidence": null,
"reasoning": "AI analysis unavailable - allowing submission",
"action": "allow",
"ai_analysis": false,
"ip_reputation": null
}

Your integration should always default to allowing submissions if the API is unreachable.