Open app
Moonborn — Developers

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_xxxxxxxxxxxxxxxx

2. 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-7 for the Soul draft and claude-sonnet-4-6 for 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