Choose the checks your application needs
ModeraLens exposes a stable category API. GET /api/v1/capabilities returns a neutral catalog of id, label, available, and description fields. available means enabled routing is configured for that category; it is not a live health probe. Your application integrates with these category IDs without depending on the underlying service implementation.
POST /api/v1/jobs accepts optional checks: a nonempty array of unique IDs from adult_nsfw, weapon, drug_like_content, graphic_violence, sensitive_document, and ai_generated. Omit checks to request the default five; AI-origin detection is opt-in. An empty array, duplicate IDs, or unknown IDs is invalid.
For files, POST /api/v1/jobs/upload uses multipart reference, images[] and either checks[] or workflow_id. The Image uploads guide covers limits and retries. Both submission modes return the same job/result contract.
The returned job includes its canonical checks list. Only requested categories appear in result.scores, result.categories, and result.checked_categories. Supported checks you did not request are listed in result.not_checked_categories; they were not assessed.
Use immutable image URLs. Completed results include image_hashes: SHA-256 hashes of the original image bytes, ordered to match request.images. Before publishing, compare the SHA-256 hash of the exact bytes you will publish with the corresponding returned hash. A result does not cover replacement bytes served later at the same URL; submit changed images as a new job.
{
"reference": "catalog-image-42",
"images": [{ "url": "https://media.example.com/image.jpg" }],
"checks": ["adult_nsfw", "weapon"]
}available reflects configured routing, not current service health or accuracy. A check listed in not_checked_categories is different from unsupported_categories, which lists capabilities outside ModeraLens’s supported catalog. Do not interpret either as a passing result.
Follow the job lifecycle
Submission is asynchronous. POST /api/v1/jobs returns HTTP 202; it does not mean the images have been checked. Jobs progress from queued to processing and then to completed or failed.
- queued: accepted and awaiting a worker.
- processing: a worker is evaluating the images.
- completed: a result is available; inspect its decision and coverage.
- failed: processing did not complete; route the content to manual review.
Do not publish content just because submission succeeded or a job stopped processing.
Retry submissions without duplicates
Send a unique Idempotency-Key containing 16–128 letters, digits, underscores, or hyphens with every new submission. Save the key with the exact request body until you know whether the request was accepted.
If a connection drops or a response is lost, retry with that same key and unchanged body. Generate a new key only for a genuinely new submission. Reusing a key with a changed payload returns HTTP 409.
const idempotencyKey = crypto.randomUUID();
const body = JSON.stringify({
reference: "catalog-image-42",
images: [{ url: "https://media.example.com/image.jpg" }],
});
// Retain idempotencyKey and body for a network retry.
const response = await fetch(`${apiOrigin}/api/v1/jobs`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body,
});Poll and paginate carefully
Retrieve GET /api/v1/jobs/{id} to observe status. Use a modest polling interval with backoff on transient errors, and stop polling once the job is completed or failed. Keep a clear timeout path that routes unresolved content to review.
The job list uses cursor pagination. Start with ?limit=20, then pass the returned meta.next_cursor as cursor. A null cursor means there are no further pages. Reset the cursor when changing the status filter.