The review engine
The check doesn’t have to live where the work does
Content gets written in a dozen places and reviewed in one. The same engine that holds the line inside our editor answers over HTTP, so the check can sit wherever the sentence is actually typed — under one set of rules, with one audit trail behind it.
Every finding, every call
How much of “our AI keeps you compliant” is a fact?
This is the question the category avoids, so it is the one the API answers on every response. Each finding carries the tier that produced it, and the body lists which of your rules landed in each.
verifiedChecked in code
A deterministic check ran over your text. A clean result here is a fact about the words, not an opinion about them.
reviewedA model looked
Useful, retrievable, and capable of being wrong. Labelled so nobody mistakes it for the row above it.
steeredNothing checked this
The rule went into a prompt and no code has looked at the result. Reported plainly, because a rule you believe is enforced and isn’t is worse than one you know is advisory.
An empty findings array does not mean compliant. It means nothing was found by the rules that actually ran — and the response tells you which those were. An integration that renders that as a green tick is making a claim this API does not make.
One rung this endpoint does not produce
Over HTTP there is no model pass. This endpoint runs the deterministic checker and calls no model, so reviewedRuleIds is empty on every response and a rule whose check is model-assisted comes back in steeredRuleIds — reported as never inspected, which is what it is. The model pass runs inside our editor and is not exposed here yet.
Two consequences worth having. There is no model latency and no model cost on a call, so the endpoint is fast and its answers are reproducible. And nothing this API returns is an opinion: every finding it produces is a fact about the text.
What actually goes wrong
None of this is about typos
The failures that cost regulated teams money and licences are ordinary and specific, and they share a shape: somebody wrote something true-sounding in a tool nobody was checking.
A claim nobody substantiated
A figure in a post that appears in no published release. In a listed company that is potential selective disclosure, and it is invisible to any tool that only matches words.
A rule that only existed in a document
The house style says never call a patient a warrior. The document says so. The person writing at 6pm on a Friday has not read it, and nothing in their editor has either.
An approval that stopped being true
Legal cleared a deck. Somebody then improved a headline. The approval still says approved, and now describes content that no longer exists.
An override nobody can find
Someone had a good reason to publish over an objection. It was a Slack message, and the person who sent it has left.
What a connection carries
Text in, findings out, your addresses preserved
Blocks of text, each with a role and your own address for it. Findings back, each carrying that address unchanged so you can mark the exact node the sentence came from. The engine never learns what a frame, a paragraph or a cell is — which is why it can be pointed at any of them.
You send
{
"workspaceId": "…",
"blocks": [{
"role": "artwork",
"location": "Frame 3 · title",
"text": "A cure for chronic fatigue.",
"ref": { "node": "12:445" }
}]
}You get back
{
"findings": [{
"statement": "Never claim a cure.",
"severity": "block",
"excerpt": "cure",
"replacement": "helps manage",
"span": { "start": 2, "end": 6 },
"ref": { "node": "12:445" },
"tier": "verified"
}],
"steeredRuleIds": ["substantiation"]
}Roles, not fields
artwork · body · caption · metadata · alt_text · notes. Platform-neutral, so one rule reaches a slide headline, a document heading and a frame title alike.
Your ref, untouched
Put whatever addresses your content. It comes back on every finding, so the result lands on the thing it is about.
Spans, not guesses
A character range into the text you sent, so you mark the words rather than the paragraph.
One engine, not one per surface
The endpoint imports the checker the editor runs
Not a port of it. Not a reimplementation kept in step by discipline. The same function.
That sounds like an implementation detail and is the whole thing. Two implementations of “is this allowed” eventually disagree, and the day they do you have content one surface cleared and another flagged. Nothing recovers a compliance tool’s credibility after that conversation.
It follows that the API cannot be more permissive than the studio. Rules set on the account hold over it, house rules included. There is no mode that checks content against rules supplied in the request — a verdict is only meaningful against a real rule set a real account owns.
checkVoice()one implementation
Everything lands in one record
Three things get called “accepting a finding”
They mean opposite things about the rule, and every other tool in this category files them as one. When somebody overrides — in our editor or through the API — which of the three they meant is recorded with it.
The rule is wrong here
It matched something it should never match.
Evidence about the rule
The rule doesn’t apply here
Correct in general, not applicable to this content.
Evidence about its scope
Shipping anyway
The rule is right, it applies, and someone decided to publish.
A record of a risk — never evidence against the rule
An override taken in another tool has to come back here rather than staying there. Five tools’ worth of overrides is not an audit trail.
Answers procurement will ask for
Keys, and what they cannot do
- Who can issue one
- An account owner, never an editor. A key is a standing grant of access to your rules, so it is a governance decision rather than an editing one.
- What it can reach
- Checking content, and recording an override. It cannot read your work, change a rule, or export — the widest key is narrower than any human role.
- Where the secret lives
- Nowhere. Only a SHA-256 is stored; the key is shown once and nobody, including us, can read it back. Revocation is immediate and permanent.
- How tenancy is enforced
- In the database, not in the application. A key resolving to one account cannot reach another’s workspace, and the refusal is identical whether that workspace belongs to someone else or does not exist.
- What happens at the limits
- Oversized requests are refused rather than truncated — 500 blocks, 20,000 characters in any one of them, 200,000 across the request. A checker that quietly skipped the last of your copy and reported no findings would be worse than one that said no.
- The rate limit, and what it is for
- 120 requests a minute per key, counted and advanced in the same statement that reads it so two simultaneous calls cannot both see a fresh window. It is a ceiling on damage rather than a commercial limit: a leaked key should cost an attacker time, and a plugin looping on an error should not be able to empty an account’s allowance before anyone notices.
Which tier this is in
Part of Pro, where brands are free and seats are not
The API is not in Studio, the single-brand tier. It comes with Pro, which is priced per seat rather than per brand — so pointing the engine at another client’s content adds nothing to the bill, and one key reaches every brand in the account.
- Included, then metered
- Pro includes a monthly call volume and meters above it. Machine traffic is the one thing this product meters, because a pipeline can run a check a second and a person cannot — and sustained volume is also the truest signal of what the engine is worth to you.
- What is never metered
- Checks run in the editor, the audit trail, and being told which tier decided. Included at every plan and never priced by the unit at any of them.
- Keys are not seats
- A key is issued by an account owner and belongs to the account rather than to a person, so adding an integration never adds a seat. Neither does adding a reviewer: a review link needs no account at all.
Start where it is easiest to see.
The editor is the fastest way to watch the engine work on your own brand — set it up, paste a post, see what it refuses. If you already know where the check needs to sit, say so and we will talk about that surface specifically.
Hosted in the EU · Append-only audit trail · No tracking scripts