# ScriptGrain API (v1)

Programmatic access to ScriptGrain: build voice profiles, generate drafts in a measured voice, and score text against a profile, with the same quality pipeline as the in-app editor.

Available on every plan, including Free. Generations consume the same credit pool as the in-app flow; there is no separate API quota. A Free account can mint a key, browse its profile, and use the free endpoints, but generation needs a paid plan's credits.

## Auth

Mint an API key in the dashboard: Settings -> API (https://scriptgrain.com/settings?tab=api). The secret (sg_live_...) is shown once, at creation.

Send it on every request:

```
Authorization: Bearer sg_live_<your-secret>
```

## Base URL

```
https://auth.scriptgrain.com/functions/v1/api-v1
```

All endpoint paths below are relative to that base.

## Endpoints

Profiles:

- `POST /v1/profiles` creates a voice profile from writing samples and starts the extraction (uses one extraction slot, same monthly caps as in-app)
- `GET /v1/profiles` lists your profiles
- `GET /v1/profiles/{id}` returns status and progress while extracting, then the narrative and all 45 measured attributes, plus `company_id` (the voice's default company, or null)

Writing:

- `POST /v1/outlines` generates an outline from a brief (free)
- `POST /v1/generations` generates a draft, either one-shot (`profile_id` + `brief` + `content_type`) or from an approved outline (`generation_id`). 1 credit per produced variant, `variants` 1-3, optional SSE streaming with `stream: true`. Every draft returns a measured `voice_match_score` and word-count self-report.
- `POST /v1/polish` revises a draft toward a voice-match target using the measured feature deltas, best-of tracked (1 credit, free skip if the draft already passes)
- `POST /v1/humanize` rewrites text to reduce AI tells while holding the voice (1 credit, free skip)
- `POST /v1/generations/{id}/edit` saves your final edit back (free; feeds closed-loop voice learning)
- `GET /v1/generations` and `GET /v1/generations/{id}` list and fetch history

Scoring and analysis (all free):

- `POST /v1/voice-match` scores any text against a profile, returning the score and per-feature deltas
- `POST /v1/compare-voice` scores up to three pieces (text or URL) against a main piece with no profile: the off-voice check, with per-feature differences

Voice Brain memory (all plans):

- `GET /v1/profiles/{id}/memory` lists the ideas, claims, stories, frameworks and topics the profile's writing has covered, each with a verbatim quote
- `POST /v1/profiles/{id}/memory/sync` indexes new drafts and samples (no credit)
- `POST /v1/profiles/{id}/novelty` checks a brief against the memory: repeats, established ideas, gaps and grounded angles (no credit)
- `GET /v1/profiles/{id}/next` proposes five angles to write next, each building on an established idea and filling a thin or stale topic (no credit)
- `POST /v1/profiles/{id}/memory/pieces` adds a piece (text or URL) to the memory and indexes it now; `POST .../memory/settings` sets `repeat_policy` (`avoid` or `allow`, i.e. similar content allowed)
- The memory keeps itself current every half hour from your drafts, edits, samples and monitored pages
- Drafts build on the memory by default once it knows ten pieces; pass `continuity: false` to write fresh

Company context (all plans):

- `GET /v1/companies` lists the companies the account can see (name, summary, audience, facts, terminology); `POST /v1/companies` creates one from a website (paid plans), a description, or manual fields (free)
- `company_id` on `POST /v1/outlines` and one-shot `POST /v1/generations` grounds the piece in that company's facts, terminology and audience, and the prompt never invents specifics. **Omit `company_id` to use the voice's default company** (set in the app under Voice Brain, when the voice has one); **pass `null` for none**. An id that does not resolve is 404 `company_not_found`; the resolved id is stored on the generation
- `GET /v1/profiles/{id}/next` angles serve the voice's company audience and facts when it has one

Page rewrite (paid plans):

- `POST /v1/profiles/{id}/rewrite-page` rewrites a public page's copy in the profile's voice, block by block with the page's images and calls to action as context (`{url}`; 1 credit per 1,500 words)

Voice monitor (paid plans):

- `GET /v1/profiles/{id}/monitor` lists the watched pages and the latest monthly run with per-page scores
- `POST /v1/profiles/{id}/monitor/urls` watches a page (`{url, label}`); `DELETE .../urls/{urlId}` stops watching it
- `POST /v1/profiles/{id}/monitor/run` runs this month's check now (once per calendar month)
- `POST /v1/ai-detect` runs the stylometric AI-writing check

Brand voice:

- `POST /v1/mimic` builds a brand profile from a public website's writing (1 brand-mimic credit; requires `consent: true`)

Billing (never plan-gated):

- `GET /v1/billing` plan, status, credits, renewal
- `GET /v1/billing/invoice` latest invoice with a PDF link
- `POST /v1/billing/checkout-link` and `POST /v1/billing/portal-link` return Stripe-hosted links; payments and plan changes always complete in the browser, never through the API

## Behaviour worth knowing

- Rate limit: 60 requests/minute per key (429 `rate_limited` beyond it).
- Credits deduct only after a variant generates successfully; failures cost nothing. Outlines are free.
- `POST /v1/generations` supports an `Idempotency-Key` header (not with `stream: true`): retries with the same key replay the stored response instead of generating and charging again.
- Errors return `{ "error": { "code", "message" } }`; every response carries an `X-Request-Id` header to quote at support.

## MCP

The same capabilities are exposed as an MCP server for Claude and other AI assistants: see https://scriptgrain.com/docs/mcp.md

Questions: support@scriptgrain.com
