Docs
get started
with riffraff.
riffraff is a spam scoring API for contact-form submissions. you send in the content; we return a verdict, a score, and the reasons. one endpoint, one token, no SDK required.
Quickstart
five steps to your first evaluation
-
1
Create your account
Sign up with your work email. You’ll land on a dashboard with a brand-new team on the free plan (1,000 evaluations / month).
-
2
Create an API token
Go to Settings → API tokens, name it something like “Production site” and copy the token once — it’s only shown the first time.
-
3
Make a test call
From your terminal:
curl -X POST https://api.riff-raff.dev/api/evaluate \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "email": "[email protected]", "subject": "quick question", "content": "Hi — do you offer…" }' -
4
Wire it into your form handler
When a submission comes in, send its fields to /api/evaluate. If is_spam is true, drop it (or stash it for review). Otherwise, carry on.
-
5
Watch it on the dashboard
Every call shows up in your dashboard with the score, reasons and which team member it was attributed to. Something flagged that shouldn’t have been? Let us know and we’ll tune the rules.
API reference
POST /api/evaluate
Submit a single piece of content for spam scoring.
Headers
| Authorization | Bearer <your-token> — required |
| Content-Type | application/json — required |
| Accept | application/json — recommended |
Body fields
| content | Required. The main message body. |
| subject | Optional. Subject line, if your form has one. |
| Optional. Sender email — used for domain / pattern checks. |
Response
what you get back
A 200 OK with a JSON body:
{
"is_spam": true,
"score": 270,
"threshold": 100,
"reasons": [
"Spam phrases detected: \"business proposal\"",
"Non-professional email domain"
]
}
- is_spam — boolean. True when score > threshold.
- score — integer. The summed weight of every rule that fired.
- threshold — integer. Currently 100. The line above which we flag spam.
- reasons — array of plain-english strings. One entry per rule that fired.
Reason catalogue
why a message got flagged
Every reason is a plain-english string. Wording can change — match on the prefix rather than the whole string if you’re doing programmatic handling.
- “Spam phrases detected: …”
- “Too many links detected: N links found (max allowed: M)”
- “Suspicious HTML tags detected: <script>, <iframe>”
- “Non-professional or suspicious email domain(s) detected: …”
- “Cyrillic characters detected”
- “Content too short: only N words (minimum M expected)”
- “Cold pitch detected: service offering language”
- “Malicious link detected: dark web marketplace domain”
- “Bot-generated name pattern detected”
Errors
what can go wrong
| Status | When |
|---|---|
| 401 | Missing, malformed or revoked token. |
| 402 | Your team’s monthly quota is spent. Response body includes plan, limit and used. |
| 422 | Validation failed — most commonly a missing content field. |
| 500 | Something unexpected on our end. Retry with exponential backoff; if it persists, shout. |
Statamic
drop-in addon
If your site runs on Statamic, the addon takes care of wiring submissions through riffraff, stashing spam reasons on the form submission, and keeping your inbox clean. Install it, paste your token, done.
Get in touch at [email protected] for the current addon package details.
Teams & billing
share the plan with your team
Every account comes with a team. Invite colleagues from Settings → Team and they all get their own login and their own API tokens, but share the plan, usage quota and dashboard.
Need more than pro’s 250k / month? Drop us a line and we’ll size something up.
FAQ
quick questions
Do you store the content I send?
Only the metadata we need to show you your usage: email, subject, score, reasons, timestamp. The full message body isn’t kept.
How is the score calculated?
A stack of deterministic rules, each with a weight. They run in isolation, scores are summed, and if the total exceeds threshold the message is flagged. No opaque ML — you get a reason for every point.
What happens if I hit my limit mid-month?
Calls return 402 with your plan’s limit and used count. Upgrade from Settings → Billing and you’re back in within a minute.
Can I run this in front of something other than Statamic?
Yes — the API is plain HTTP. The Statamic addon is a convenience; plenty of customers call the API directly from Laravel, Node, Go, or whatever stack they’re on.
Something got flagged that shouldn’t have.
Send the details to [email protected]. We tune rules continuously based on real false-positive reports.
ready to stop reading junk?
free tier, no card, ~30 seconds to first evaluation.