Saltar al contenido principal

Antispam & Antiphishing

The antispam API inspects a message (SMS, WhatsApp, email) and returns a verdict — clean, spam, or phishing — with a severity score, a plain-language explanation, and the URLs it found. Use it to block, quarantine, or flag messages before they reach your users.

POST /api/v1/antispam — requires an API key with the antispam scope. The full request and response are in the interactive API Reference; this page explains how to read the result.

Authentication​

X-Tenant-Id: <your tenant id>
X-Api-Key: <your API key>

Sync vs. async (polling)​

By default the check is synchronous — the verdict is in the response. You can also run it asynchronously: the call returns immediately with a job id you poll (or receive via webhook), so you never block on a longer check.

Opt into async any of these ways:

  • query — POST /api/v1/antispam?async=true
  • header — Prefer: respond-async
  • body — { "async": true }

Requests that include attachments are always asynchronous — each attachment is deep-scanned (which can take several seconds), so the call never blocks on a verdict.

An async request returns 202:

{ "status": "queued", "jobId": "…", "filescan_job_ids": ["…"] }

Poll for the result:

curl -s https://shield.orbis.roundbox.dev/api/v1/antispam/JOB_ID \
-H "X-Tenant-Id: $TENANT_ID" -H "X-Api-Key: $API_KEY"
# → { "status": "queued|running|done|failed", "result": { …verdict… }, "error": null }

When status is done, result has the same shape as the synchronous response, with each attachment's scan outcome under result.filescan[]. If you've configured a webhook, it also fires on completion with that payload. Each attachment is a separate file-scan (own quota/price) and is individually pollable via GET /api/v1/files/{jobId}.

Reading the response​

{
"inspectionId": "26bc4f0d-ac21-407b-bf21-bb452cd17319",
"verdict": "phishing",
"score": 46,
"modelAvailable": true,
"rationale": "Dangerous: this message uses a shortened link and pushes you to “verify” a delivery, a common scam. Do not click it; go to the delivery company’s official app instead.",
"urls": ["http://bit.ly/verify-now"],
"lang": "en",
"elapsedMs": 6884,
"layers": [ "…per-layer evidence…" ]
}

verdict — the decision​

verdict is the authoritative classification and the field your integration should act on:

verdictMeaningTypical action
cleanNo spam or phishing indicatorsDeliver normally
spamUnsolicited / bulk, low targetingQuarantine or route to junk
phishingCredential theft, impersonation, or a malicious lureBlock and alert

score — the severity​

score is 0–100 and expresses how strong the signal is. Use it to prioritise or sort — not to derive the category (that's verdict).

scoreReading
0–24Low
25–59Elevated
60–100High

Because a strong indicator can drive a phishing verdict even at a modest score, you may see verdict: "phishing" with a mid-range score. Always act on verdict; treat score as confidence.

Other fields​

  • rationale — a plain-language, safe-to-display explanation of the verdict.
  • urls — URLs and hosts found in the message (including any decoded from QR codes), each checked against ROUNDBOX threat intelligence.
  • modelAvailable — true when the full AI analysis was applied.
  • elapsedMs — how long the check took, end to end, in milliseconds.
  • layers — per-layer evidence behind the verdict: each entry has a layer id, a 0–100 contribution, and human-readable signal strings you can log or display.
nota

The antispam response never includes any pricing or cost information.

Offensive-language filtering (opt-in)​

Set "checkOffensiveLanguage": true on the request (or tick the box in the console) to also screen the message for offensive / foul language — in English, Spanish, and Central-American Spanish. Off by default.

When offensive language is detected, the response is blocked:

{
"verdict": "clean",
"blocked": true,
"blockReason": "offensive-language",
"offensive": {
"severity": "high",
"categories": ["profanity", "insult"],
"matchedCount": 2,
"maskedRationale": "Message blocked for offensive language (profanity, insult)."
}
}
  • blocked / blockReason are separate from verdict — a message can be verdict: "clean" (not spam or phishing) yet blocked: true for offensive language.
  • The offensive object is safe to show end users: severity, category labels, and a match count. The maskedRationale never reprints the offending words — they are always masked.
  • Add your own blocked words under Account settings → Offensive Language; they apply on top of the built-in dictionaries.

Scanning attachments for malware​

The antispam endpoint inspects the message body and its URLs. To scan files for malware — with antivirus signatures, heuristics, and (on premium plans) behavioral sandboxing, including encrypted archives — use the dedicated file-scan endpoint:

  • POST /api/v1/files — scan a file (requires the filescan scope). See File Inspection.

Test it with EICAR​

EICAR is the industry-standard benign antivirus test file — safe to use, and every scanner flags it — so it's the right way to prove detection end to end, including inside a password-protected zip.

# 1. Create the EICAR test file
printf '%s' 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' > eicar.com

# 2. Wrap it in a password-protected zip ("infected" is a recognised test password)
zip --password infected eicar.zip eicar.com

# 3. Submit it (force=true skips any cached verdict so the engines actually run)
curl -s https://shield.orbis.roundbox.dev/api/v1/files \
-H "X-Tenant-Id: $TENANT_ID" \
-H "X-Api-Key: $API_KEY" \
-F "file=@eicar.zip" \
-F "password=infected" \
-F "force=true"
# → { "status": "pending", "jobId": "job-abc123" }

Then poll for the verdict:

curl -s https://shield.orbis.roundbox.dev/api/v1/files/job-abc123 \
-H "X-Tenant-Id: $TENANT_ID" \
-H "X-Api-Key: $API_KEY"
# → { "status": "done", "verdict": "malicious", … }

Shield opens the archive and scans the file inside it, returning a malicious verdict for EICAR. A plain eicar.com works too — just send it as file with force=true.