Skip to main content
Documentation
Learning Center

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

Quick Links

Quick Start Guide

To moderate content with Discuse, send a POST to https://api.discuse.com/api/v2/check with an X-API-Key header and a JSON body containing the text, image URLs, or file URLs you want checked. The response returns a per-category breakdown and a single has_violations flag. This guide walks through that first call, the response format, and basic error handling — about five minutes end to end.

Prerequisites

Before you begin, make sure you have:

  1. A Discuse account (sign up at discuse.com)
  2. An API key from your dashboard
  3. A tool for making HTTP requests (cURL, Postman, or your application code)

Step 1: Get Your API Key

After signing up, navigate to your dashboard and locate the API Keys section. Click "Create New Key" to generate a new API key. Keep this key secure - it provides access to your account and usage quota.

Every Discuse key starts with the disc_ prefix, for example:

disc_aB3dEf6GhIjKlMnOpQrStUvWxYz012345-_6789

Step 2: Make Your First API Call

The simplest way to test the API is with a text analysis request. Here's a basic example using cURL:

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": "Hello, this is a test message to analyze!"
    }
  }'

Step 3: Understand the Response

A successful request returns a JSON response with analysis results:

{
  "has_violations": false,
  "cached": false,
  "results": {
    "hits": false,
    "sentiment": {
      "is_negative": false,
      "is_toxic": false,
      "score": 0.03,
      "toxic": 0.02,
      "profanity": 0.01,
      "threat": 0.00,
      "insult": 0.03,
      "hit": false
    },
    "spamfinder": {
      "label": "ham",
      "confidence": 0.08,
      "is_spam": false,
      "hit": false
    },
    "language": {
      "language": "en",
      "confidence": 0.98
    }
  },
  "usage": {
    "api_requests_used": 42,
    "api_requests_limit": 1000,
    "api_requests_remaining": 958
  }
}

processing_time_ms is only included when timing is enabled in your project settings, and message is only set on quota-exceeded responses — so both are omitted from the example above.

Response Fields Explained

Field Description
has_violations Boolean: true if any enabled check flagged the content (mirrors results.hits)
cached Whether this result was served from cache (still counts one request against quota)
results.hits Overall hit flag across all checks
results.sentiment Toxicity scores from 0.0 (safe) to 1.0 (highly toxic), plus is_toxic/hit decision flags
results.spamfinder Spam verdict: label, confidence, is_spam (raw) and hit (threshold-aware)
results.language Detected language code and confidence
usage Your API request count, limit, and remaining quota for the current billing period

Step 4: Analyze an Image

To check an image for NSFW content, include the image URL in your request:

curl -X POST https://api.discuse.com/api/v2/check \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "content": {
      "image_urls": ["https://example.com/image.jpg"]
    },
    "settings": {
      "check_images": true
    }
  }'

Step 5: Combine Multiple Checks

You can analyze text and images together in a single request:

{
  "content": {
    "text": "Check out this amazing photo!",
    "image_urls": ["https://example.com/photo.jpg"]
  },
  "settings": {
    "check_sentiment": true,
    "check_spam": true,
    "check_images": true,
    "check_language": true
  }
}

Integration Examples

JavaScript/Node.js

async function checkContent(text) {
  const response = await fetch('https://api.discuse.com/api/v2/check', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.DISCUSE_API_KEY
    },
    body: JSON.stringify({
      content: { text }
    })
  });

  return response.json();
}

// Usage
const result = await checkContent('Hello world!');
if (result.has_violations) {
  console.log('Content flagged:', result.message);
}

Python

import requests
import os

def check_content(text):
    response = requests.post(
        'https://api.discuse.com/api/v2/check',
        headers={
            'Content-Type': 'application/json',
            'X-API-Key': os.environ['DISCUSE_API_KEY']
        },
        json={
            'content': {'text': text}
        }
    )
    return response.json()

# Usage
result = check_content('Hello world!')
if result['has_violations']:
    print(f"Content flagged: {result['message']}")

Does caching count against my quota?

Discuse caches results for identical content for a few minutes. When a response comes back with "cached": true, it was served from cache, so it returns faster and skips re-running the checks. The request still counts as one API request against your quota, but you are not re-billed for the underlying per-feature scans (image, antivirus). Caching mainly helps when the same content is submitted repeatedly in a short window.

How do I handle errors?

A successful check returns HTTP 200. A failed key, rate limit, or malformed request returns a non-2xx status. Note that quota exhaustion is not an HTTP error: when your billing period quota is used up, the API still returns 200 with has_violations: false and a message explaining the quota was exceeded — check the message and usage fields rather than relying on a status code.

try {
  const response = await fetch('https://api.discuse.com/api/v2/check', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': apiKey
    },
    body: JSON.stringify({ content: { text } })
  });

  if (!response.ok) {
    if (response.status === 401 || response.status === 403) {
      throw new Error('Invalid or unauthorized API key');
    } else if (response.status === 429) {
      throw new Error('Rate limit exceeded - slow down requests');
    }
    throw new Error(`API error: ${response.status}`);
  }

  const result = await response.json();

  // Quota exhaustion is returned as a 200 with a message, not an error status.
  if (result.message && result.usage && result.usage.api_requests_remaining === 0) {
    console.warn('Quota exceeded:', result.message);
  }

  return result;
} catch (error) {
  console.error('Content check failed:', error);
  throw error;
}

Next Steps

Now that you've made your first API call, explore these resources:

Written by the Discuse Team · Last updated June 2026

Related Articles

What is Content Moderation?

Understanding content moderation fundamentals and why it matters for your platform

Authentication and API Keys

How to authenticate requests and manage your API keys securely

Error and Response Codes

HTTP statuses, the quota-exhausted 200 response, and how to handle API errors correctly