VoxGuardAPI

VoxGuard API documentation

VoxGuard API is a developer-focused profanity detection service. It exposes a single JSON endpoint backed by the integrated open-source profanity_php PHP library - a deterministic word-list and phrase-search engine that runs entirely inside this application. There is no external AI service in the request path.

Base URL: https://voxguard.alphascripts.us.cc/api/v1/check
Protocol: HTTPS recommended (HTTP works but is not secure)
Format: application/json request and response

Authentication

Every request authenticates with an API key sent in the X-API-Key header:

X-API-Key: vg_live_YOUR_KEY_HERE
  • Missing key → 401 missing_api_key
  • Unknown or mistyped key → 401 invalid_api_key
  • Revoked key → 403 revoked_api_key
  • Expired key → 403 expired_api_key
  • Suspended account → 403 account_suspended

API key generation

  1. Create an account and open API Keys in the dashboard.
  2. Click New API key, give it a descriptive name (Production Website, Tournament Chat, ...).
  3. Choose a language scope and expiration (see below).
  4. The full key (vg_live_…) is displayed exactly once. Copy it immediately - only a SHA-256 hash is stored server-side.
vg_live_<40-character base64url secret>
prefix stored for lookup: vg_live_XXXXXXXX....
stored server-side:       SHA-256(full key)

Language selection

The optional language field controls which word list is loaded. Accepted values:

  • A two/three-letter code supported by the library (for example "en", "de", "hi") - see the full list.
  • "auto" - detect from the request's Accept-Language header (only for keys with the All supported languages scope).
  • Omitted - defaults to "en", or to the key's language scope if the key is restricted to a single language.

A key created with a single-language scope rejects every other language with 403 language_not_in_scope. Unknown codes return 422 unsupported_language.

Accuracy note: the library tokenises on whitespace. Languages written without spaces between words (for example Chinese or Japanese) are only detected when the flagged token appears as a whitespace-separated chunk. Latin-script languages and languages with spaces (English, Spanish, German, Hindi, Russian, ...) work as expected.

Expiration settings

Keys can be created with no expiration, a fixed lifetime (1, 7, 30 or 90 days) or a custom date and time. Expiration is validated on every request; expired keys return 403 expired_api_key and are marked expired in the dashboard.

Request format

POST https://voxguard.alphascripts.us.cc/api/v1/checkContent-Type: application/json
X-API-Key: vg_live_YOUR_KEY

{
  "text": "This is a sample message",
  "language": "en"
}
FieldTypeRequiredDescription
textstringYes Message to screen. Empty is allowed and returns contains_profanity: false. Maximum 5000 characters (→ 413 text_too_long).
languagestringNo Supported code or "auto". Defaults to "en" (or the key scope).

Response format

Success (HTTP 200)

{
  "success": true,
  "data": {
    "contains_profanity": false,
    "language": "en",
    "checked_languages": ["en"],
    "detection_method": "none",
    "normalization_applied": []
  },
  "meta": {
    "request_id": "6f1c2a8e-3d4b-4a51-9f66-0a1c9f1c2a8e",
    "duration_ms": 4,
    "engine": "profanity_php",
    "noise_filter": true,
    "rate_limit": { "limit": 60, "remaining": 59 }
  }
}

Error (4xx / 5xx)

{
  "success": false,
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded (minute window). Retry after 27 seconds.",
    "retry_after": 27,
    "scope": "minute"
  },
  "meta": { "request_id": "...", "duration_ms": 2 }
}
Honest mapping of the library result: profanity_php returns a boolean only. VoxGuard therefore returns contains_profanity, the language(s) checked, and timing metadata - it never fabricates matched-word lists or confidence scores. The noise_filter meta flag indicates whether VoxGuard's documented false-positive filter was applied on top of the raw library verdict (details).

Obfuscated text detection

Each request runs three layers in order. The original text is never modified - only internal candidates are checked and discarded:

  1. library - the upstream library on the raw text (with the noise filter).
  2. library_normalized - the library re-run on up to five normalized candidates (lowercase, Unicode look-alike confusables, leet digits/symbols such as 0→o / @→a, punctuation inserted between letters like f.u.c.k, spaced letters like f u c k, and repeated-character collapsing like fuuuuck). Each candidate is a full pipeline run, so the noise filter applies identically. data.normalization_applied lists which step triggered.
  3. alias - exact whole-token matching against VoxGuard's Hinglish / alternative-spelling dictionary (config/profanity-aliases.php). Never substring matching, so class cannot match an ass alias. data.matched_term (only present on alias hits) returns the canonical dictionary term, never raw user input.

data.detection_method is one of library, library_normalized, alias or none. The alias layer runs for every request regardless of the selected API language.

Supported languages

Exactly the languages shipped by the installed library (75 codes):

af am ar az be bg ca ceb cs cy da de dz el en eo es et eu fa fi fil fr gd gl hi hr hu hy id is it ja kab kh ko la lt lv mi mk ml mn mr ms mt my nl no pih piy pl pt ro rop ru sk sl sm sq sr sv ta te tet th tlh to tr uk uz vi yid zh zu

Error codes

HTTPCodeMeaning
400invalid_jsonBody is not valid JSON or is empty.
401missing_api_keyNo X-API-Key header.
401invalid_api_keyKey does not exist or the hash does not match.
403revoked_api_keyKey was revoked.
403expired_api_keyKey passed its expiration date.
403account_suspendedAccount suspended by an administrator.
403language_not_in_scopeLanguage outside the key's scope.
405method_not_allowedOnly POST is accepted.
413payload_too_largeRequest body over 1 MB.
413text_too_longtext exceeds the configured limit.
415unsupported_media_typeContent-Type must be application/json.
422missing_text / invalid_texttext field missing or not a string.
422unsupported_languageLanguage code not shipped by the library.
429rate_limit_exceededPer-key quota exceeded (Retry-After header set).
500internal_errorUnexpected server error (details are logged, never returned).
503service_unavailableAPI disabled or in maintenance.

Rate limits

Limits are enforced per key using fixed windows stored in MySQL: 60 requests / minute and 5000 requests / day by default (configurable by the administrator). Successful responses include:

X-RateLimit-Limit: 60X-RateLimit-Remaining: 42

When the quota is exceeded the response is 429 with a Retry-After header in seconds. Rate-limit counters are cheap fixed-window rows - one row per key per window - so the database stays small even under load.

Note: unlimited API keys do not mean unlimited capacity - every key receives its own quota within platform limits.

Security practices

  • Send keys only from server-side code. Never embed a key in browser JavaScript, mobile apps or public repositories.
  • Store keys in environment variables or a secrets manager; rotate by creating a new key and revoking the old one.
  • Always use HTTPS so the header cannot be read in transit.
  • Validate responses and handle non-2xx statuses gracefully - treat the API as fail-closed for moderation (block or queue on error, do not silently allow).
  • VoxGuard stores only hashes of keys and passwords, uses CSRF tokens, prepared statements, login throttling and per-key rate limits.

Example integrations

curl -X POST https://voxguard.alphascripts.us.cc/api/v1/check \
  -H "Content-Type: application/json" \
  -H "X-API-Key: vg_live_YOUR_KEY" \
  -d '{"text":"You are an asshole","language":"en"}'
<?php
function voxguard_check(string $text, string $apiKey, string $language = 'en'): array
{
    $payload = json_encode(['text' => $text, 'language' => $language], JSON_UNESCAPED_UNICODE);

    $ch = curl_init('https://voxguard.alphascripts.us.cc/api/v1/check');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_HTTPHEADER     => [
            'Content-Type: application/json',
            'X-API-Key: ' . $apiKey,
        ],
        CURLOPT_POSTFIELDS     => $payload,
    ]);

    $body = curl_exec($ch);
    $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);

    if ($body === false) {
        throw new RuntimeException('VoxGuard request failed: ' . $error);
    }

    $json = json_decode($body, true);
    if (!is_array($json)) {
        throw new RuntimeException('VoxGuard returned a non-JSON response (HTTP ' . $status . ')');
    }
    $json['_http_status'] = $status;
    return $json;
}

try {
    $result = voxguard_check('your message here', getenv('VOXGUARD_API_KEY'));
    if ($result['success'] && $result['data']['contains_profanity']) {
        // reject or queue the message for review
    }
} catch (Throwable $e) {
    // fail closed: queue the message instead of broadcasting it
    error_log($e->getMessage());
}
<?php
// Native PHP HTTP stream context - no cURL extension required.
$context = stream_context_create([
    'http' => [
        'method'        => 'POST',
        'header'        => "Content-Type: application/json\r\n"
                         . "X-API-Key: " . getenv('VOXGUARD_API_KEY') . "\r\n",
        'content'       => json_encode(['text' => $message, 'language' => 'en']),
        'timeout'       => 15,
        'ignore_errors' => true,   // capture 4xx/5xx bodies instead of failing
    ],
]);

$body = file_get_contents('https://voxguard.alphascripts.us.cc/api/v1/check', false, $context);
if ($body === false) {
    throw new RuntimeException('VoxGuard unreachable');
}

$status = 0;
foreach ($http_response_header as $header) {
    if (preg_match('#^HTTP/\S+\s+(\d{3})#', $header, $m)) {
        $status = (int) $m[1];
    }
}

$result = json_decode($body, true);
$flagged = $status === 200 && !empty($result['success'])
    && $result['data']['contains_profanity'];
POST /api/v1/check HTTP/1.1
Host: your-domain.com
Content-Type: application/json
X-API-Key: vg_live_YOUR_KEY
Content-Length: 51

{"text":"sample message","language":"en"}

# Any REST client (Postman, Insomnia, httpie, requests):
http POST https://voxguard.alphascripts.us.cc/api/v1/check \
  X-API-Key:vg_live_YOUR_KEY \
  text=="sample message" language=="en"
Security warning: only call VoxGuard from a server-side runtime. Never put your API key in front-end JavaScript, mobile bundles or public repos - anyone who sees it can consume your quota.
// Server-side Node.js (CommonJS) - keep VOXGUARD_API_KEY in your environment.
async function voxguardCheck(text, language = 'en') {
  const res = await fetch('https://voxguard.alphascripts.us.cc/api/v1/check', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.VOXGUARD_API_KEY,
    },
    body: JSON.stringify({ text, language }),
  });

  const data = await res.json().catch(() => null);

  if (res.status === 429) {
    const retryAfter = Number(res.headers.get('Retry-After') || 5);
    throw new Error(`Rate limited, retry in ${retryAfter}s`);
  }
  if (!res.ok || !data || data.success !== true) {
    throw new Error(`VoxGuard error ${res.status}: ` +
      (data?.error?.message || 'unknown'));
  }
  return data.data; // { contains_profanity, language, checked_languages }
}

// Usage: check before broadcasting a message.
module.exports = { voxguardCheck };

AI integration prompt

Copy this prompt into your coding assistant to integrate VoxGuard into another project:

Integrate the VoxGuard API (profanity detection) into this project.

Endpoint: POST https://voxguard.alphascripts.us.cc/api/v1/checkHeaders:  Content-Type: application/json
          X-API-Key: <key from environment variable VOXGUARD_API_KEY>
Body:     {"text": "<user message>", "language": "en"}

Requirements:
1. Create a small reusable client module (PHP, Node or the project's language)
   that sends the message text and returns the parsed JSON response.
2. NEVER place the API key in client-side code, mobile bundles, or the repo.
   Read it from an environment variable or secrets store only.
3. Call the endpoint from the BACKEND before a message is stored, broadcast,
   or published (chat, comments, reviews, support tickets).
4. Handle failures explicitly: 401/403 => log and treat the message as
   unverified; 429 => retry later or queue; 5xx / network errors => fail closed
   (hold the message for review, do not silently broadcast it).
5. Use response.data.contains_profanity === true to flag the message;
   surface response.meta.request_id in logs for support.
6. Respect the input limit (response 413 text_too_long) by truncating or
   rejecting oversized input before calling the API.
7. Add a config flag (e.g. VOXGUARD_ENABLED) so the integration can be turned
   off in development, defaulting to ON in production.
8. Write tests covering: clean message, flagged message, missing key,
   rate-limit handling and timeout behaviour.

Troubleshooting

SymptomCause / fix
401 invalid_api_key Whitespace or a line break in the key, a revoked key, or a key from another environment. Copy the full key again (it is shown only once).
415 unsupported_media_type Missing Content-Type: application/json.
400 invalid_json Single quotes, trailing commas, or an empty body - send valid JSON.
429 rate_limit_exceeded Quota reached. Honour Retry-After or ask the admin to raise the limit in Admin → App Settings.
Clean text flagged (false positive) The upstream list is generated from raw entries with digits/symbols stripped (e.g. a55 → a), which can flag ordinary words. VoxGuard applies a documented false-positive filter by default; the admin can switch to strict raw library mode. Report specific phrases for the exclusion list.
Obvious profanity not flagged Check the language scope of the key, and note that languages without whitespace word boundaries are only partially detected by the library. No detection engine is 100% accurate - add a secondary review step for high-risk content.
503 service_unavailable The API is disabled or in maintenance mode (App Settings).

Health check

Public health information is available at /status.php and as JSON at /status.php?format=json. The documentation URL itself never contains secrets.