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/jsonrequest 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
- Create an account and open API Keys in the dashboard.
- Click New API key, give it a descriptive name (Production Website, Tournament Chat, ...).
- Choose a language scope and expiration (see below).
- 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'sAccept-Languageheader (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.
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"
}
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | Message to screen. Empty is allowed and returns contains_profanity: false.
Maximum 5000 characters (→ 413 text_too_long). |
language | string | No | 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 }
}
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:
- library - the upstream library on the raw text (with the noise filter).
- 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 likef.u.c.k, spaced letters likef u c k, and repeated-character collapsing likefuuuuck). Each candidate is a full pipeline run, so the noise filter applies identically.data.normalization_appliedlists which step triggered. - alias - exact whole-token matching against VoxGuard's Hinglish /
alternative-spelling dictionary (
config/profanity-aliases.php). Never substring matching, soclasscannot match anassalias.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):
Error codes
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_json | Body is not valid JSON or is empty. |
| 401 | missing_api_key | No X-API-Key header. |
| 401 | invalid_api_key | Key does not exist or the hash does not match. |
| 403 | revoked_api_key | Key was revoked. |
| 403 | expired_api_key | Key passed its expiration date. |
| 403 | account_suspended | Account suspended by an administrator. |
| 403 | language_not_in_scope | Language outside the key's scope. |
| 405 | method_not_allowed | Only POST is accepted. |
| 413 | payload_too_large | Request body over 1 MB. |
| 413 | text_too_long | text exceeds the configured limit. |
| 415 | unsupported_media_type | Content-Type must be application/json. |
| 422 | missing_text / invalid_text | text field missing or not a string. |
| 422 | unsupported_language | Language code not shipped by the library. |
| 429 | rate_limit_exceeded | Per-key quota exceeded (Retry-After header set). |
| 500 | internal_error | Unexpected server error (details are logged, never returned). |
| 503 | service_unavailable | API 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"
// 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
| Symptom | Cause / 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.