Getting started

Quickstart

Make your first rewrite and detection call in under five minutes.

This page takes you from zero to a working rewrite and a detection result. You need a terminal and an account; everything below works with a test key, which returns realistic responses and never uses your plan's words.

Get a test key

Open the dashboard, go to API keys and create a key in test mode. Test keys start with sk_test_. Copy it once; we only show the full value at creation.

export API_KEY="sk_test_..."   # keep this out of source control

Tip:

Store the key in your secret manager or a local .env file that is ignored by git. Never ship it in browser code.

Make your first rewrite

Send a draft to POST /rewrite. The example below uses a voice id and the blog platform preset; you can drop voice_id to use the neutral house voice until you've created your own.

curl -X POST https://api.intactvoice.com/v1/rewrite \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Many businesses struggle to create useful blog posts because the writer receives only a topic. Escalate any case older than 14 days.",
  "voice_id": "voice_8f2k1x",
  "platform": "blog",
  "strength": "standard",
  "fidelity": "strict"
}'

Rewrites are asynchronous by default. The call returns 202 Accepted with a job straight away; completion time depends on input length, pipeline stages and queue depth.

{
  "id": "job_01JD4QC7",
  "object": "job",
  "type": "rewrite",
  "status": "queued",
  "estimated_seconds": 35,
  "poll_url": "/v1/jobs/job_01JD4QC7"
}

Wait for the job.succeeded webhook, or poll GET /jobs/{job_id} every few seconds. The finished job carries the rewritten text, a fidelity report and before/after detection scores:

curl https://api.intactvoice.com/v1/jobs/job_01JD4QC7 \
  -H "Authorization: Bearer $API_KEY"
{
  "id": "rw_01JD4Q8ZK3",
  "object": "rewrite",
  "model": "rewrite-2026-10",
  "duration_ms": 34210,
  "text": "Most blog posts go wrong before anyone writes a word: the writer gets a topic and nothing else. If a case is older than 14 days, escalate it.",
  "fidelity": {
    "status": "pass",
    "checks": [
      {
        "type": "number_unit",
        "source": "14 days",
        "output": "14 days",
        "ok": true
      }
    ],
    "changed_facts": []
  },
  "signals": {
    "source": {
      "ai_likelihood": 0.91
    },
    "output": {
      "ai_likelihood": 0.14
    }
  },
  "usage": {
    "words_in": 22,
    "words_out": 28,
    "words_billed": 22
  }
}

Check the fidelity report

Every number, unit, name and link in the source was extracted and compared against the output. In the example,14 days survived unchanged, so fidelity.status is pass.

With fidelity: "strict" (the default) a changed fact never ships: the API returns 422 fidelity_failed with the facts that moved, and the request is not billed. Read Fidelity checks for the full rule set.

Score a text with Detect

POST /detect returns an overall ai_likelihood, a confidence level driven by length, and the reasons: per-sentence signals and document-level structure.

curl -X POST https://api.intactvoice.com/v1/detect \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "In today'\''s fast-paced world, side hustles are more than just extra cash. In this post, we'\''ll explore…",
  "granularity": "sentence",
  "explain": true
}'

Note:

A detection score is a signal, not proof of authorship. See Detection signals before using scores in any decision about a person.

Go live

  1. Create a voice from real samples

    Upload 2–20 pieces by the person you write for with POST /voices. Pass the returned id as voice_id.

  2. Swap in a live key

    Create an sk_live_ key with only the scopes you need. Live requests use your plan's monthly words.

  3. Handle failures

    Treat 422 fidelity_failed as a normal outcome (send the draft to a human), and retry 429 / 5xx with backoff. See Errors.

Next steps