API

Integrate the pre-review. Mint a key, run it live, ship it.

Any writing tool, script-coverage service, or production workflow can call the same review this site uses. There is no account: press the button, get a key, and run a live review from this page. Anonymous calls work too, at lower limits.

Keys are stateless HMAC tokens signed with a secret held in Google Secret Manager, so verification is a signature check with no key store. Every response carries data.disclaimer as a required field and meta.gate with the thresholds that were evaluated. Errors use one envelope: { ok:false, error:{ code, message, fix, docs } }.

Mint a key

Returned once, never stored. Expires after 90 days. Cannot be revoked individually; mint one per integration.

Run it live from here

Runs the real pipeline with your key: deterministic triggers, Google Agent Search retrieval, the GuidanceContextReviewer on Vertex AI Agent Engine (or in-process ADK, recorded in meta.agent_runtime), and Model Armor on the answer. Nothing is cached.

Mint a key first, or run anonymously at the standard limit.

Request

curl -X POST "$BASE/v1/review" -H "content-type: application/json" -d '{"preset_id":"guidance-case","region":"US"}'

Response

—

Call it from your code

Python

import requests

BASE = ""
key = requests.post(f"{BASE}/v1/keys").json()["data"]["api_key"]
r = requests.post(
    f"{BASE}/v1/review",
    headers={"Authorization": f"Bearer {key}"},
    json={"screenplay": open("draft.fountain").read(), "region": "US"},
)
review = r.json()
print(review["meta"]["gate"])            # which thresholds passed and failed
for note in review["data"]["grounded_flags"]:
    for clause in note["clauses"]:
        print(note["heading"], clause["publisher"], clause["source_url"])
print(review["data"]["disclaimer"])      # required field on every response

JavaScript

const BASE = "";
const { data: { api_key } } = await (await fetch(`${BASE}/v1/keys`, { method: "POST" })).json();
const res = await fetch(`${BASE}/v1/review?format=markdown`, {
  method: "POST",
  headers: { "content-type": "application/json", "x-api-key": api_key },
  body: JSON.stringify({ preset_id: "responsible-depiction", region: "US" }),
});
console.log(await res.text()); // a Markdown report, disclaimer first

Reference

Endpoints

RouteWhat it doesKey
POST /v1/reviewReview a screenplay (screenplay or preset_id, optional region). ?format=markdown returns a downloadable report. Returns scenes, trigger candidates, grounded notes with cited clauses, the ADK explanation, writer controls, resources, disclaimer, and meta.gate.Optional · 6/min anonymous, 30/min keyed
POST /v1/review/streamThe same review as newline-delimited JSON progress events (parsed, retrieving, retrieved, explaining, explained, complete) ending with result or error. This is what the workbench uses.Same as review
POST /v1/reportRender a Markdown report from a review payload you already hold. No model call.No
GET /v1/presets, /v1/presets/{id}, /v1/presets/{id}/downloadThe demo library and downloads in fountain, txt, or json.No
GET /v1/evidenceThe research behind the guidance: 14 verified records with DOI and PMID, findings, and the trigger classes each bears on. Retrieved per note as grounded_flags[].evidence.No
GET /v1/guidanceThe approved corpus with provenance and corpus_version.No
GET /v1/resources?region=Region-aware support resources.No
GET /v1/eval/latestThe deterministic-layer benchmark, computed live from the shipped 48 cases, with failures listed.No
POST /v1/keys, GET /v1/keys/selfMint a key; inspect the identity and limits of the key you send.—
GET /v1/stack, /health, /health/integrationsWhich Google Cloud and Replit services are answering right now, with evidence.No
POST /v1/exports, GET /v1/exports/{id}Store a review result only when asked. Replit App Storage on Replit; a temporary file elsewhere.Optional
GET/POST/DELETE /v1/decisions, GET /v1/meSaved writer decisions for a signed-in Replit Auth user. Never stores screenplay text.Replit Auth

Full OpenAPI: /docs · /openapi.json. Limits are per minute per caller. Anonymous callers keep working when keys are unavailable. Retention: nothing is stored by default; exports and decisions are explicit. Logged per review: request id, caller tier, counts, model, latency. Never logged: screenplay text, prompts, generated prose.

Response envelope

{
  "ok": true,
  "data": { "scenes": [...], "grounded_flags": [...], "trigger_candidates": [...],
            "grounding_status": "available", "writer_controls": [...],
            "resources": [...], "disclaimer": "...", "decision_owner": "writer",
            "overall_score": null },
  "meta": { "request_id": "req_…", "latency_ms": 8420, "verdict": "notes",
            "caller": { "tier": "keyed", "key_id": "…" },
            "gate": { "passed": ["deterministic_candidate_present", …], "failed": [] },
            "model_versions": { "gemini": "gemini-2.5-flash", "google_adk": "2.7.1" },
            "corpus_version": "…", "abstained_because": null }
}

Error envelope

{
  "ok": false,
  "error": { "code": "rate_limited",
             "message": "review allows 6 requests per minute for this caller.",
             "fix": "Wait and retry, or POST /v1/keys for a key with 5x this limit.",
             "docs": "/docs" },
  "meta": { "request_id": "req_…" }
}

Codes are stable strings: validation_error, invalid_api_key, rate_limited, grounding_failed, agent_review_failed, sign_in_required, api_keys_unavailable. Failures fail closed: no note is ever fabricated from model memory.