API Docs

Voice profiles, in your register

Train on a sample of your writing. Apply the profile to a humanization. The output reads like you.

Overview

What a profile captures

A voice profile distills writing-style features from a sample you provide — n-gram fingerprints, sentence-length distribution, burstiness, vocabulary specificity, hedging density, and a handful of register signals. Those features don’t leave our database, but their summary statistics get baked into the prompt for any humanization that references the profile.

Apply a profile by sending its voice_profile_id in the upload form for POST /api/v1/documents/upload. The output then reads in your voice rather than the generic register the model would otherwise default to.

Voice profiles are Pro and Enterprise plan features. Free-tier requests that include avoice_profile_id are rejected with HTTP 402.

Create

POST /api/v1/voice-profiles/

JSON body: name (string, up to 80 chars) and sample_text (the writing you want the profile trained on). Send at least 1,500 words; 3,000+ gets noticeably better results because the distributional features stabilize.

Response (HTTP 201):

{
  "id": "vp_01HX...",
  "name": "Sermon voice",
  "sample_text_length": 4218,
  "features_extracted": 47,
  "created_at": "2026-05-13T14:22:11Z"
}

curl

curl -X POST https://api.inksong.app/api/v1/voice-profiles/ \
  -H "X-API-Key: ink_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sermon voice",
    "sample_text": "Long passage of your own writing here..."
  }'

Python

import os
import requests

sample = open("my-writing.txt").read()
response = requests.post(
    "https://api.inksong.app/api/v1/voice-profiles/",
    headers={"X-API-Key": os.environ["INKSONG_API_KEY"]},
    json={"name": "Sermon voice", "sample_text": sample},
)
response.raise_for_status()
profile = response.json()
print(profile["id"])

JavaScript

import fs from "node:fs/promises";

const sample = await fs.readFile("my-writing.txt", "utf8");
const response = await fetch("https://api.inksong.app/api/v1/voice-profiles/", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.INKSONG_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "Sermon voice", sample_text: sample }),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const profile = await response.json();
console.log(profile.id);

List

GET /api/v1/voice-profiles/

Returns an array of your profiles. To keep response payloads lean, the sample text is omitted from list responses — you get the metadata only (id, name, lengths, timestamps). Fetch the single-profile endpoint if you need the original sample.

curl

curl https://api.inksong.app/api/v1/voice-profiles/ \
  -H "X-API-Key: ink_live_YOUR_KEY"

Get one

GET /api/v1/voice-profiles/{id}

Returns the full profile record, including the original sample_text so you can review what trained the profile.

curl

curl https://api.inksong.app/api/v1/voice-profiles/vp_01HX... \
  -H "X-API-Key: ink_live_YOUR_KEY"

Delete

DELETE /api/v1/voice-profiles/{id}

Returns HTTP 204 with an empty body. Idempotent — deleting an already-deleted profile (or one that never existed under your account) also returns 204. Documents already humanized with a now-deleted profile are unaffected; the profile features were baked into that run.

curl

curl -X DELETE https://api.inksong.app/api/v1/voice-profiles/vp_01HX... \
  -H "X-API-Key: ink_live_YOUR_KEY"

Applying

Reference a profile in an upload

On POST /api/v1/documents/upload, include voice_profile_idas a form field. The features extracted at profile-creation time get composed into the Claude prompt for this humanization run, and the output is steered toward your distribution rather than the model’s default register.

curl

curl -X POST https://api.inksong.app/api/v1/documents/upload \
  -H "X-API-Key: ink_live_YOUR_KEY" \
  -F "file=@draft.docx" \
  -F "tone=balanced" \
  -F "humanness_level=60" \
  -F "voice_profile_id=vp_01HX..."