Content Moderation API Pricing: Cost Per 1,000 Requests

Integration is the easy half. Once POST /moderation returns a categories object with twelve booleans and a single flagged value, the questions that follow are operational: content moderation API pricing at your volume, what the moderation API character limit does to your request count, and how much of the pipeline you build yourself because there is no batch endpoint and no webhooks.
This article works through the arithmetic using the numbers the documentation publishes and nothing else. Every rate, limit and status code below comes from the Cloud API reference or the pricing page. The estimates are yours to redo with your own average input length.
If you have not made a call yet, adding a content moderation API in an afternoon covers the request shape first.
What Actually Counts as One Moderation Request
The usage-based price and the 3,000-character unit
The cloud API is usage-based at $0.40 USD per 1,000 requests. A request covers up to 3,000 characters. The endpoint accepts text of up to 10,000 characters, and a call is checked in 3,000-character pieces, with each started piece counting as one request.
That produces a short set of arithmetic rules:
- A 2,000-character comment is 1 request.
- A 3,000-character text is still 1 request.
- A 3,001-character text is 2 requests, because the second piece has started.
- A 7,000-character article is 3 requests: 3,000 + 3,000 + 1,000.
- A full 10,000-character text is 4 requests: 3,000 + 3,000 + 3,000 + 1,000.
The request itself is plain JSON:
curl -X POST https://api.cautionlabs.com/moderation \
-H "Authorization: Bearer $CAUTIONLABS_CLOUD_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Your text goes here."}'The response is a set of flags, not a report:
{
"categories": {
"toxic": false,
"profanity": false,
"hate": false,
"harassment": false,
"self_harm": false,
"adult": false,
"violence": false,
"drugs": false,
"weapons": false,
"pii": false,
"spam": false,
"minor": false
},
"flagged": false
}Authentication is a Cloud API key sent as a bearer token. A private (on-premises) key does not work against the hosted API.
Why boolean responses make the math simple
The response schema is twelve booleans plus an overall flagged value that is true when any category is true. There are no scores, no probabilities and no confidence values, and there are no thresholds to tune.
For cost planning that has three consequences worth stating plainly:
- Billing is per request, not per category. A text that trips
pii,spamandtoxicat once costs the same as a text that trips nothing. - There is no tuning knob that changes call volume. A score-based system can tempt you into re-running text at a different cutoff; here the output is a fixed set of flags, so one call is one answer.
- Storage is cheap. You are persisting booleans next to a content record, not a vector or a score history. That keeps the moderation table small and the audit trail easy to reason about.
Estimating Your Monthly Moderation Bill
Working from average input length and message volume
You need two numbers you already have: your average input length in characters, and your daily item volume. Everything else is multiplication.
Here is a walkthrough with a comment platform. Suppose the average comment is 400 characters, so each comment is one request. At 50,000 comments per day, that is 50,000 requests per day. Over a 30-day month that is 1,500,000 requests. Divide by 1,000 to get 1,500 pricing units, multiply by $0.40, and the month lands at $600.
Now suppose a support-ticket system where the average ticket body is 6,000 characters. That is two requests each, because 3,000 + 3,000 covers it exactly. At 20,000 tickets per day you send 40,000 requests per day, which is 1,200,000 requests per month, or 1,200 units. At $0.40 per unit that is $480 per month.
The general formula in prose: monthly requests equal daily items multiplied by pieces per item multiplied by the number of days you operate. Monthly cost equals monthly requests divided by 1,000, multiplied by $0.40.
If you want a quick text moderation API cost calculator, a two-input spreadsheet is enough. Column one is average length, column two is daily volume. The one derived value you need is pieces per item, which is the average length divided by 3,000 and rounded up to the next whole number. From there the rest is arithmetic.
The most sensitive lever is average input length, because it moves items across a piece boundary. Dropping an average from 3,100 characters to 2,900 characters removes one request from every item at that average, which for a million items a month is a thousand units. Trimming boilerplate, footers and quoted replies before sending is often the single largest cost reduction available to you, and it does not change which flags you get back.
When a one-time model purchase changes the shape
The pricing model is not tiered — the rate is flat at $0.40 per 1,000 requests, and requests are paid for with credits on your account. That makes forecasting linear, which is usually what finance wants from a moderation line item.
There is a second option with a different shape. On-premises is a one-time payment of $299 USD per model. The first model is Argus 1 (model id argus_1), and the purchase includes unlimited installs and unlimited requests, plus upgrades to that model. Both deployment paths return true/false flags across the twelve categories; the difference is where the compute runs and how you pay for it.
A simple break-even framing: $299 at $0.40 per 1,000 requests equals 747,500 requests. Below roughly that volume in your planning horizon, the usage-based cloud API is the smaller line item. Above it, and especially if you already run GPUs, the one-time purchase is worth pricing out with your own infrastructure numbers. The decision is volume-driven and operations-driven rather than feature-driven.
The natural next reads are on-premises vs cloud content moderation for the trade-off, and deploy the on-premises model with Docker if you have decided to run it yourself.
Handling Text Longer Than a Single Request
Long-form articles, documents and transcripts
The endpoint accepts up to 10,000 characters. Anything longer has to be split by your application code before sending. The documentation does not describe any server-side handling beyond that, so plan for splitting to be your responsibility.
Split on paragraph or sentence boundaries rather than at a fixed offset. A flag is more useful when it is attributable to a section of a document than when it points at an arbitrary character range, and your reviewers will thank you for not cutting sentences in half.
PIECE = 3_000
def split_for_moderation(text: str, size: int = PIECE) -> list[str]:
"""Split on paragraph boundaries where possible, never above `size`."""
pieces: list[str] = []
buffer = ""
for paragraph in text.split("\n\n"):
candidate = f"{buffer}\n\n{paragraph}" if buffer else paragraph
if len(candidate) <= size:
buffer = candidate
continue
if buffer:
pieces.append(buffer)
buffer = ""
while len(paragraph) > size:
pieces.append(paragraph[:size])
paragraph = paragraph[size:]
buffer = paragraph
if buffer:
pieces.append(buffer)
return piecesEach returned piece is one call to POST /moderation, and each started 3,000-character piece inside that call counts as one request.
Splitting strategy is a cost lever
Because each started 3,000-character piece is a request, how you chunk is a direct cost decision. Chunking at 3,000 characters means an 8,700-character article becomes three requests, since two full pieces and a partial piece have started. Chunking smaller gives you finer attribution and a longer list of flagged sections, at the price of more requests.
The splitting approach you choose should follow the product question you are answering. If you need to point a reviewer at a specific flagged passage, smaller pieces are worth the extra requests. If you only need a document-level decision, larger pieces are cheaper.
Long generated text is the most common case here — see checking LLM output for how that pipeline is usually shaped. If you are implementing the split in Python, the Python integration tutorial covers the request path you will be looping over.
Batching, Queues and Webhooks: What You Build Yourself
No batch endpoint, no webhooks
The API has no batch endpoint and sends no webhooks. There is one POST /moderation call that takes one text. That means content moderation API batch requests are a client-side concept: grouping, fan-out, retries and result delivery are your own design decisions.
This is not a gap so much as a boundary. JSON in, JSON out, twelve booleans and one flagged value means a consumer in your queue has no configuration to get wrong and no state to carry between calls.
Designing an internal moderation queue
The pattern that works well is a small internal queue with four responsibilities:
- Enqueue the text plus a reference to your own content record.
- Call
POST /moderationwith a concurrency cap you have chosen and documented. - Store the returned flags next to that content record, so the result is durable and queryable.
- Expose the outcome to the rest of your product through your own event mechanism.
async function moderate(text, contentId) {
const response = await fetch("https://api.cautionlabs.com/moderation", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.CAUTIONLABS_CLOUD_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ text }),
});
if (!response.ok) {
throw Object.assign(new Error("moderation failed"), {
status: response.status,
});
}
const result = await response.json();
// result.categories holds twelve booleans; result.flagged is the overall value
return { contentId, ...result };
}The payoff is a user-facing write path that stays fast: you accept the comment, publish or hold it according to your own policy, and let moderation run alongside the request rather than in front of it. The result lands on the content record when it lands.
The same shape applies if you are working in Node — the Node.js integration tutorial shows the call itself, which is the part your queue workers wrap.
Concurrency, Retries and Avoiding Wasted Spend
Client-side limits since rate limits are not published
The documentation does not publish rate limits, does not describe 429 responses, and does not define rate-limit headers. Moderation API throughput planning therefore happens on your side: choose a concurrency ceiling, a backoff schedule and a timeout, write them down in your runbook, and tune them against observed behaviour in your own environment rather than against a published number.
A useful default posture is a fixed-size worker pool, a bounded queue, and a timeout short enough that a stuck socket does not hold a worker hostage. Because each call is independent and stateless, adding workers is the straightforward way to raise throughput.
Caching identical text
If the same string can reach moderation twice, you are paying twice. Duplicate comments, resubmitted forms, retried submissions and repeated boilerplate are all common sources. Cache the moderation result keyed by a hash of the exact text and reuse the stored flags.
A cache also protects you from your own retry logic. If a write path retries after a network blip, the cached flags mean the retry does not become a second billable request.
Retrying only the errors that deserve it
The API documents the error shape as a code and a message, with invalid_request, unauthorized, insufficient_credits, wrong_key_type and internal_error as the possible codes, returned alongside status codes 400, 401, 402, 403 and 500.
Split those into two groups when you write your retry policy:
- Retry with bounded backoff:
500andinternal_error. These are the ones where trying again has a chance of a different outcome. Cap the attempts. - Do not retry blindly:
400withinvalid_request,401withunauthorized,402withinsufficient_credits,403withwrong_key_type. These point at the request or the credential, so repeating the same call produces the same result and burns requests while hiding a bug you would rather see in your logs.
The production debugging guide to error codes goes through each of these in detail. Treat a 401 or 403 as an alert, not a queue item.
Cutting Request Volume Without Cutting Coverage
Moderate what users see
The cheapest request is the one you never send. Decide deliberately which surfaces need moderation and which do not: the text that becomes visible to other users, the text you store long-term, and the text that leaves your system. Surface-specific scoping — comments, bios, direct messages, generated output — keeps coverage where it matters and keeps request counts tied to real exposure.
Choosing split granularity
For long documents, choose your split size on purpose rather than by convenience. A coarser split means fewer requests and a document-level verdict; a finer split means more requests and a passage-level verdict. Neither is universally right, but the cost difference between them is predictable, which makes it a decision you can make on the whiteboard instead of in production.
One structural advantage of a boolean design is forecasting. There is no threshold to retune, so a change in your moderation policy does not quietly change your monthly request count. The cost model has one input that matters — how many pieces of text you send — and everything else is deterministic.
Frequently Asked Questions
Is there a batch endpoint? No. The API exposes a single POST /moderation endpoint that takes one text per call, and no batch endpoint is documented. Grouping many texts into one job is something you build in your own queue. The API also sends no webhooks, so result delivery is yours to implement as well.
Are there rate limits? The documentation does not publish rate limits, 429 responses or rate-limit headers. Concurrency caps, backoff and timeouts are client-side decisions you make and document in your own runbook. Plan against your own infrastructure and error handling rather than against a published ceiling.
How much does it cost per 1,000 requests? The cloud API is usage-based at $0.40 USD per 1,000 requests, and one request covers up to 3,000 characters. On-premises is a different shape: a one-time payment of $299 USD per model, starting with Argus 1, which includes unlimited installs and requests plus upgrades to that model.
Does a longer text cost more? Yes, up to the endpoint's 10,000-character limit. Text of up to 3,000 characters is one request, and each additional started 3,000-character piece is another request, so a 10,000-character text is four requests. Anything above 10,000 characters must be split by your own application code before it is sent.
Start With Your Own Numbers
Review the API reference and the pricing page, send a POST /moderation request for a text you already have, and estimate your monthly request volume from your own average input length. Two inputs — average characters and daily items — are enough to turn this article into a number for your next planning meeting.
If the projected volume starts competing with a one-time purchase, read on-premises vs cloud content moderation before you commit. Either way, the response you get back is the same twelve booleans and one overall flagged value, so the integration work you do now carries over.