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"
}
| Field | Type | Required | Description |
|---|---|---|---|
form_data | object | Yes | Key-value pairs of submitted form fields |
behavioral_score | number | No | Client-side human-likeness score (0-100). Defaults to 50 |
form_context | string | No | Description of this specific form's purpose |
site_url | string | No | The website URL the form is on |
form_id | string | No | Unique identifier for the form |
ip_address | string | No | Submitter'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
}
}
| Field | Type | Description |
|---|---|---|
intent | string | null | AI classification result (see table below) |
confidence | number | null | Confidence score (0-100) |
reasoning | string | 1-2 sentence explanation of the classification |
action | string | Recommended action: allow, flag, or block |
ai_analysis | boolean | Whether AI analysis was performed (false on free tier) |
ip_reputation | object | null | IP intelligence data (Growth+ tiers with IP tracking enabled) |
Intent Values
| Intent | Action | Description |
|---|---|---|
legitimate | allow | Real person with genuine inquiry |
spam | block | Generic spam content |
bot | block | Automated/bot submission |
phishing | block | Phishing or social engineering attempt |
irrelevant | flag | Real submission but not relevant to the business |
suspicious | flag | Uncertain, needs human review |
IP Reputation Object
Returned only for Growth and Agency tiers with IP tracking enabled.
| Field | Type | Description |
|---|---|---|
threat_level | string | low, medium, high, or critical |
fraud_score | null | Reserved for future use |
country | string | null | Two-letter country code (ISO 3166-1) |
is_vpn | boolean | Whether the IP belongs to a VPN provider |
is_tor | boolean | Whether the IP is a Tor exit node |
is_proxy | boolean | Whether 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.