Build your first persona
From a one-line intent to a fully audited, four-layer persona with a captured voice fingerprint — in five minutes.
This tutorial walks through POST /v1/personas end-to-end: getting an
API key, sending an intent, reading the response, and finding the
persona again later. Everything else in the docs builds on this loop.
1. Get an API key
Sign in to your workspace, open Settings → API keys → New key. Two prefix conventions:
sk_test_*— bound to a test workspace; isolated from production data.sk_live_*— production. Treat it like a database password.
Store the key in an environment variable so it doesn't end up in your shell history:
export MOONBORN_API_KEY=sk_live_xxxxxxxxxxxxxxxx2. Generate a persona
A single POST call hands an intent to the six-step
generation pipeline. The
workspaceId is the only other required field; everything else has a
defensible default.
curl -X POST https://api.moonborn.co/v1/personas \
-H "Authorization: Bearer $MOONBORN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"intent": "A 34-year-old founder from Istanbul. Brilliant but restless. Hides imposter syndrome behind relentless momentum.",
"workspaceId": "ws_..."
}'import Moonborn from '@moonborn/sdk';
const client = new Moonborn({ apiKey: process.env.MOONBORN_API_KEY });
const persona = await client.personas.createPersona({
intent:
'A 34-year-old founder from Istanbul. Brilliant but restless. Hides imposter syndrome behind relentless momentum.',
workspaceId: 'ws_...',
});
console.log(persona.id, persona.status, persona.pipelineRunId);import os
from moonborn import Moonborn
client = Moonborn(api_key=os.environ["MOONBORN_API_KEY"])
persona = client.personas.create_persona(
intent="A 34-year-old founder from Istanbul. Brilliant but restless.",
workspace_id="ws_...",
)
print(persona.id, persona.status, persona.pipeline_run_id)The response is intentionally lean:
{
"id": "persona_01H...",
"status": "active",
"pipelineRunId": "run_01H..."
}The persona itself — Soul, Self, Mask, Surface — is now in your
workspace. The pipelineRunId is the breadcrumb to the
audit trace if you want to see
per-step latencies and provider routes.
3. Read the persona back
const detail = await client.personas.getPersona({ id: persona.id });
console.log(detail.surface.name.display);
console.log(detail.mask.signaturePhrases);
console.log(detail.voiceFingerprintId);What you get back is the full four-layer document plus runtime hints
(voice fingerprint ID, distinctiveness score, audit verdict). See the
GET /v1/personas/{id} endpoint
for the schema.
4. Stream the pipeline (optional)
For a UX that shows pipeline progress, pass stream: true. The
response becomes an SSE stream of step.started / step.completed /
pipeline.completed events. See the
Streaming patterns guide for the read loop.
What you didn't have to do
- Choose a model. Moonborn picked
claude-opus-4-7for the Soul draft andclaude-sonnet-4-6for the rest, both configurable at org/workspace scope. - Run the audit. It ran automatically; a 4.2/5 verdict was stored alongside the persona.
- Compute a voice fingerprint. Fifty short-scenario completions ran post-generation; the embedding is queryable.
Next
- Open a chat session against your new persona: Set up a chat session.
- Watch for drift in long conversations: Handle voice drift.
- Browse the full Personas API.