Unslop APIv1.3.0

API guide and examples

Use Unslop from a script or another application. This guide describes version 1.3.0. The generated OpenAPI reference lists every accepted field; the API explorer lets you try requests in the browser.

You can create an account and get an API key immediately. Save the key and recovery code when shown. The workbench also accepts your signed-in browser session. Documentation is public. Agents can register over HTTP. Prepaid requests use a human-funded balance, spending caps and idempotency headers; see pricing.

Your account and API key

Sign up with a username and password. Save the API key and recovery code when shown. You can use the workbench immediately, or send the key in the Authorization: Bearer header from your application.

Free accounts have daily word, request, and AI-call limits. The signup page lists the current allowances, and GET /v1/usage reports yours. AI calls also share a service-wide daily allowance. Retrying a rewrite or adding meaning review uses more calls. Daily limits reset at midnight UTC; request-per-minute limits reset at the next UTC minute.

You can replace or revoke your key on the account page. A new key immediately replaces the old one, so update any scripts that use it. Rotating a key doesn't reset usage or remove profiles. Save your recovery code: there is no email password reset.

Make your first request

The base URL is https://unslopapi.vercel.app. Send JSON with Content-Type: application/json and your key in the Authorization: Bearer header. Keep keys in your server or local environment, not in public website code.

Save the analysis example below as analysis.json. Set UNSLOP_KEY in your environment, then run:

curl --fail-with-body https://unslopapi.vercel.app/v1/analyze \
  -H "Authorization: Bearer $UNSLOP_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary @analysis.json

This request runs deterministic analysis and makes no AI calls. A rewrite that passes its gate and starts generation sends original excerpts and guidance to the selected providers. Each model attempt consumes one account AI call. Skipped rewrites still count as requests and consume the submitted-word allowance.

Copyable request examples

These are request bodies, not recorded responses or promises about a model's output. Save the one you need to a JSON file and use the matching endpoint in the command above.

Analyze a draft without AI

POST /v1/analyze. The ceiling asks whether the estimated grade is at most 8; easier text passes.

{
  "text": "It's worth noting that we fixed the search page. Your saved filters now work again. You can open the page, choose a filter, and see the matching notes without setting it up again.",
  "genre": "technical",
  "allow_ai": false,
  "include": ["score", "quality", "explain", "inspect"],
  "constraints": { "readability_ceiling": 8 }
}

Request a limited rewrite

Every AI rewrite, including AI proofreading, first checks the original. By default it needs at least 50 prose words and a style score of 20/100. Set rewrite_gate.threshold and rewrite_gate.minimum_words per request to change the cutoffs, or rewrite_gate.enabled: false to bypass them while still scoring the original. If the enabled gate fails, status: "skipped" returns the original with zero generation or meaning-review calls. Free-text instructions and voice profiles cannot override these structured settings. Ordinary deterministic proofreading is unaffected. This is a provisional editing threshold, not a validated authorship test.

POST /v1/rewrite. The default mixed provider alternates OpenAI and Anthropic. Each call proposes one small patch against the original text; the server assembles them. Select openai or anthropic to restrict processing to one provider. This example allows four generation calls, including any retries, plus one meaning review.

{
  "text": "It's worth noting that we fixed the search page. Your saved filters now work again. You can open the page, choose a filter, and see the matching notes without setting it up again.",
  "provider": "mixed",
  "rewrite_gate": { "enabled": true, "threshold": 5, "minimum_words": 30 },
  "micro": { "max_calls": 4, "max_span_words": 8, "max_span_chars": 60 },
  "allow_ai": true,
  "semantic_review": true,
  "retry_on_failure": true,
  "genre": "technical",
  "instructions": "Keep the facts. Remove unnecessary introductions. Keep the term saved filters.",
  "constraints": {
    "max_change_ratio": 0.15,
    "readability_ceiling": 8,
    "protected_terms": ["saved filters"],
    "preserve_numbers": true
  }
}

The example lowers the gate to a score of 5 and 30 words for a short passage. Omit rewrite_gate to keep the defaults of 20 and 50. Short-text scores are less informative. A tight change budget and a demanding reading target may conflict. If the candidate can't meet both, the API returns the original. It never silently loosens your limits.

Check a revision you already have

POST /v1/verify. This example uses code only. Changing 12 to 13 should fail the number-preservation check even though the edit is small.

{
  "original": "We shipped 12 fixes on Friday.",
  "revised": "We shipped 13 fixes on Friday.",
  "allow_ai": false,
  "constraints": { "max_change_ratio": 0.35, "preserve_numbers": true }
}

Save explicit writing preferences

POST /v1/profiles. The returned id can be supplied as profile_id on later analysis or rewrite requests.

{
  "name": "Plain project updates",
  "genre": "technical",
  "instructions": "Use direct language. Preserve qualifications and technical terms.",
  "rules": [{
    "id": "prefer.use",
    "type": "prefer",
    "phrase": "utilize",
    "replacement": "use",
    "description": "Prefer the simpler word when it fits.",
    "auto_fix": false
  }],
  "samples": [],
  "defaults": { "max_change_ratio": 0.35 }
}

Profiles are saved in your workspace. To replace or delete one, send its current revision in the X-Profile-Revision header. Request rules override profile rules with the same ID, and request constraints override profile defaults.

Put instructions in instructions and approved prose in samples. Profile import proposes rules for review; it does not save them automatically. Profile defaults hold constraints only. Supply gate settings, micro limits, provider selection, and review preferences on each request.

Read the response before using the text

Analysis fields below are at the top level of /v1/analyze. A rewrite includes them under before and after, unless return_analysis: false. The individual /score, /quality, and /explain endpoints return their selected object directly.

Useful response fields
FieldMeaning
score.style_scorePattern density from 0 to 100. Lower means fewer matched style patterns. It is not an authorship probability.
qualityMechanics, reading level, rhythm, and descriptive voice-sample comparisons. Some results are null or insufficient when the sample is too small.
explain.findingsLocations, rule IDs, matched text, and explanations. New rhythm and repetition suggestions have scored: false.
acceptedWhether the candidate passed hard constraints and any performed meaning review. Read status first: skipped or unchanged text can still have accepted: true. This does not mean an edit or review occurred.
textThe accepted revision, or the original when a candidate was rejected. An accepted result may be unchanged.
validation.checksEach requested mechanical check is passed, failed, or unverified. Failed or unverified hard checks reject a rewrite.
original_score / rewrite_gateThe original score and the decision to permit AI editing, always included even with return_analysis: false. passed is true when the configured size and score requirements pass, or when you explicitly disable the gate. Reasons are insufficient_text, below_style_threshold, style_threshold_met, or disabled. The same gate appears under rewrite_gate in /score responses.
attemptsOne record per patch-generation call, with original offsets, provider, model, acceptance, and rejection reasons. Invalid patches are discarded; optional retries share the call budget.
micro_editingCall counts, limits, coverage, completion reason, and accepted patches with original offsets and provider/model attribution. spans_remaining counts unreviewed spans. A partially_rewritten result contains accepted edits with incomplete coverage; unchanged output can also have incomplete coverage.
finding_changesRaw before/after counts per rule in the returned text. A lower density score alone can result from added filler.
usageOn rewrite responses, total input and output tokens from the rewrite and review calls made in that request.

Rewrite statuses: skipped means the score gate failed; unchanged means no change was returned; partially_rewritten means accepted changes with unreviewed spans; rewritten means accepted changes after all planned spans were reviewed; constraints_unsatisfied means final validation or meaning review rejected the candidate. Per-call acceptance in attempts does not override the final accepted value. A completed scan does not prove every possible improvement was found.

HTTP 200 can include accepted: false and status: "constraints_unsatisfied". That means the service ran successfully and rejected the edit. Rejected candidate differences remain in validation.comparison for diagnosis; do not automatically apply them.

On /v1/verify, constraints_satisfied covers mechanical checks only. If you enable AI review there with allow_ai: true and semantic_review: true, read the separate semantic result too.

Controls and units

The table lists top-level rewrite fields. Gate and micro settings use their own nested objects; edit budgets, reading targets, output limits, and preservation flags belong inside constraints. Unknown fields are rejected. Omitted object fields keep their defaults.

Rewrite request controls
FieldBehavior
allow_aiDefaults true only on /rewrite; explicitly send true for AI proofreading, profile import, or review. Most other text endpoints default false.
providermixed (rewrite default), openai, or anthropic. Mixed alternates the two configured models. Model IDs and credentials are service configuration, not request fields.
instructions, tone, audienceRewrite guidance: up to 6,000, 200, and 200 UTF-16 units respectively. Guidance does not override hard constraints or structured gate settings.
profile_id, rules, writing_samplesA saved workspace profile, up to 100 literal/contextual rules, and up to four approved prose samples. Same-ID request rules override profile rules.
locale, format, genreEnglish dialect defaults to en-US; also GB, CA, AU. Format is plain (default) or markdown. Genre is optional: general, technical, business, personal, educational, or creative.
semantic_reviewDefaults false. One review of the assembled candidate if it contains edits and passes mechanical checks. It uses the next provider in the rotation and counts outside micro.max_calls; account allowance reserves one call for it.
retry_on_failureDefaults false. At most one retry per invalid patch, within the same generation budget. It does not retry final meaning-review failures or provider errors.
return_edits, return_analysisBoth default true. False omits the top-level character diff or before/after analysis respectively. Original score, gate, validation, attempts, and micro_editing.patches still return.

/proofread defaults to reporting findings. apply:true applies conservative deterministic corrections. Adding allow_ai:true uses the score gate and AI micro-editing, with the default micro limits and one provider (OpenAI unless specified). It does not accept rewrite-only fields such as micro, instructions, or provider:"mixed"; use /rewrite for those controls. /review chooses its model with reviewer; /verify uses provider for optional meaning review. Neither is blocked by the rewrite gate.

These request settings complement provider, micro, constraints, rules, writing_samples, instructions, tone, audience, semantic_review, retry_on_failure, and response-detail flags. Account quotas, maximum request size, available models, and server-enforced upper bounds remain service limits. The exact fields and ranges are in OpenAPI. GET /v1/capabilities reports the configured models and engines. This avoids relying on a model name copied from an older example.

Troubleshooting

Common outcomes and next steps
OutcomeWhat to check
400The JSON body could not be parsed.
401Supply a valid workspace key in the Bearer header. Reading a public page doesn't grant API access.
403Check origin and session access. Account cookies require the same origin; cross-origin applications need a bearer key and an allowed origin.
404Check the endpoint or profile ID. Profiles are private to their workspace.
413The body is too large. Requests are limited to 256 KB; individual text fields also have schema limits.
415Send Content-Type: application/json.
422Read error.details when present. Unknown fields, conflicting targets, invalid spans, or missing AI consent can cause rejection.
409 or 428 on a profileRead the current profile revision and include it in X-Profile-Revision. Another edit may have changed the revision.
429Read the error code. Minute limits reset at the next UTC minute; daily word/model limits reset at midnight UTC. Avoid immediate retry loops.
500An unexpected server error occurred. Keep the request ID for the owner; do not include keys or private text in a report.
502 or 503A provider or required service failed or is unavailable. The owner needs to check model credentials, access, and billing. An unchecked rewrite isn't accepted.
Original text returnedInspect status and rewrite_gate first, then accepted, checks, and any meaning review. A gate skip is not a provider error. Only loosen a constraint when you intend to permit more change.
No rhythm warningWarnings need enough prose: 10 sentences or 5 paragraphs. Structured Markdown blocks can be excluded. The absence of a warning isn't proof of quality.

When reporting a problem, keep the request_id or X-Request-Id value. Don't include your key. Share submitted text only if you intend the recipient to see it.

Data, consent, and usage

Deterministic analysis runs on the server without a model call. Rewriting and optional review send the relevant text and guidance to the chosen providers; mixed editing uses both OpenAI and Anthropic. Saved profiles persist in workspace storage; prepaid requests may briefly cache response text for retries. See billing and retention. See where your text goes.

Public prepaid accounts allow 20 requests per minute, 500 requests per day, 100,000 submitted words per day and 100 model calls per day. When billing is disabled, the trial allowance is 10,000 words and 5 calls per day. Individual keys can have different limits. GET /v1/usage reports yours. All submitted string values, including samples, instructions, and rule text, count toward words; failed provider attempts count toward calls.

External detector or watermark requests require allow_external: true and an approved, configured provider. Reading the static reference pages makes no API or model calls. A score-gate skip uses no AI calls but still counts toward request and word allowances. Mixed mode may reach only one provider when its call budget is one; providers_used reports generation calls, and semantic_review.model identifies any reviewer. Retry and meaning review are off by default. Each patch-generation attempt counts as one call; retries use the generation budget and meaning review adds at most one call.

Back to top | How Unslop works | Try the API explorer