Skip to main content
Documentation
Learning Center

Master content moderation with comprehensive guides, tutorials, and API documentation

Quick Links

Combined Multi-Check Requests

You don't need one API call per check. A single POST /api/v2/check can run text, image, badword, and antivirus checks together over mixed content, and return one response with a result for each. This is the most efficient way to moderate a post that has a caption, an image, and an attachment all at once.

Why moderate everything in one call?

A user submission is usually a bundle: text plus media plus links. Calling the API separately for each part means more round trips, more latency, and more quota spent. One combined request runs the enabled checks in parallel and gives you a single verdict to act on.

How do I run several checks at once?

Put each kind of content in content, enable the checks you want in settings, and read the per-check results. Each enabled check runs against the matching content.

curl -X POST https://api.discuse.com/api/v2/check \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "content": {
      "text": "Great deal, check my profile!",
      "image_urls": ["https://example.com/post-image.jpg"],
      "document_urls": ["https://example.com/attachment.pdf"]
    },
    "settings": {
      "check_spam": true,
      "check_sentiment": true,
      "check_images": true,
      "check_antivirus": true
    }
  }'

Response

{
  "has_violations": true,
  "cached": false,
  "results": {
    "hits": true,
    "spamfinder": { "label": "spam", "confidence": 0.91, "is_spam": true, "hit": true },
    "sentiment": { "is_negative": false, "is_toxic": false, "score": 0.1, "hit": false },
    "images": { "status": "OK", "porn": 0.02, "sexual": 0.05, "neutral": 0.93, "hit": false },
    "antivirus": { "status": "OK", "hit": false, "details": [] }
  },
  "usage": {
    "api_requests_used": 530,
    "api_requests_limit": 10000,
    "api_requests_remaining": 9470
  }
}

How do I read the combined result?

Use has_violations for the overall decision, then look at each results.<check>.hit to see which check fired and why:

Field Meaning
has_violations True if any enabled check flagged the content — your one-line verdict
results.hits The same overall signal inside the results object
results.spamfinder.hit Spam fired (threshold-aware; gate on hit, not raw is_spam)
results.sentiment.hit Toxic/negative sentiment over your thresholds
results.images.hit An image was over your NSFW threshold
results.antivirus.hit Malware found in a document
results.badwords.hit A configured badword matched
results.skipped_features Checks that were requested but not run (e.g. a feature whose quota is exhausted)

Only the checks you enabled (and that had matching content) appear in results. A check with no content to act on — check_images with no image_urls — simply doesn't run.

Which content pairs with which check?

Check Content it reads
check_sentiment, check_spam, check_badwords, check_language content.text
check_images content.image_urls
check_antivirus content.document_urls

A single request can carry up to 10 image URLs, 5 document URLs, and text up to 10,000 characters. Send a submission's parts together rather than splitting them across calls.

What about partial failures?

If one check errors (say an image URL is unreachable) the others still return — you get the results that succeeded, and the failed check reports its error/empty result rather than failing the whole request. Decide per check: block on a confirmed hit, and choose whether an errored check should fail open or queue for review.

Best practices

Enable only what you need

Each enabled check adds work. Turn on the checks that match the content you actually receive — there's no benefit to running check_antivirus on text-only messages.

One verdict, then drill down

Branch on has_violations first for the fast path, then inspect results only when you need to know which check fired (for logging, appeals, or routing to the right reviewer).

const res = await check(content, settings);
if (!res.has_violations) return allow();

const r = res.results;
if (r.antivirus?.hit) return quarantine();      // most severe first
if (r.images?.hit)    return blockMedia();
if (r.spamfinder?.hit || r.badwords?.hit) return shadowban();
return queueForReview(r);

Related

Written by the Discuse Team · Last updated June 2026

Related Articles

Text Analysis and Sentiment Detection

Detect spam, toxicity, profanity, and analyze sentiment in text content

Image NSFW Detection

Automatically detect and filter inappropriate images and adult content

Spam Detection

AI-powered spam filtering for text and messages