Personas
A persona is the simulated customer: who they are, what they object to, what they are keeping to themselves, and how they speak.
List personas
GET /api/nn-coach/personas — any member
Create a persona
POST /api/nn-coach/personas — manager or above
{
"name": "Sceptical SMB owner",
"grounding_mode": "archetype",
"language": "en-IN",
"profile": {
"role": "Owner of a 12-person interiors firm",
"budget": "tight, needs to see payback within a year"
},
"personality": { "warmth": "low", "patience": "short", "directness": "high" },
"objections": [
{
"trigger": "price is mentioned",
"objection": "That's well above what we budgeted.",
"resolvable_by": "a payback calculation over 12 months"
}
],
"hidden_state": { "already_has_supplier": true, "contract_ends": "March" },
"speech_profile": {
"median_words_per_turn": 12,
"p90_words_per_turn": 28,
"filler_tokens": ["hmm", "acha"],
"code_switch_rate": 0.2,
"question_ratio": 0.3,
"interrupts_agent": true,
"avg_turns_before_hangup": 14
},
"voice_config": { "speaker": "ritu" }
}
| Field | Required | Notes |
|---|---|---|
name | ✓ | |
grounding_mode | — | archetype (default), twin, or replay — enforced by a database constraint |
consent_basis | — | Required when grounding_mode is twin |
profile | — | Free-form facts about the customer |
personality | — | Free-form behavioural dials |
objections | — | What they push back on, and what resolves it |
hidden_state | — | What they know but will not volunteer |
speech_profile | — | How they talk — see below |
language | — | |
voice_config | — | Pins a TTS speaker, e.g. {"speaker": "ritu"} |
An unknown speaker is rejected here rather than surfacing as a provider error in the middle of someone's practice call:
{ "detail": "unknown voice ritu — call GET /api/nn-coach/voices for the list" }
Leaving voice_config out lets the service pick a speaker matching the
persona's gender at call time.
Grounding modes
| Mode | What it means |
|---|---|
archetype | An invented customer type. The default, and the safe one |
twin | Modelled on a real identified customer |
replay | Reconstructed from a real recorded call |
twin requires consent_basis — a persona modelled on a real person needs a
stated legal basis before it can be created. The API refuses without it.
Objections
{
"trigger": "price is mentioned",
"objection": "That's well above what we budgeted.",
"resolvable_by": "a payback calculation over 12 months"
}
resolvable_by is what makes a scenario teachable rather than merely hard. It
tells the simulated customer what would actually change their mind, so a rep
who does the right thing is rewarded and one who talks around it is not.
Speech profile
This is what stops every persona sounding like the same model. Median and p90
words per turn set how much they say; filler_tokens and code_switch_rate
set how they say it; interrupts_agent decides whether they talk over the rep
— which is what makes barge-in worth testing in voice mode.
avg_turns_before_hangup gives an impatient customer somewhere to go: they
leave, and the rep has to earn the conversation.
Delete a persona
DELETE /api/nn-coach/personas/{uuid} — manager or above
Scenarios referencing it lose their customer, so remove those first.
Voices
GET /api/nn-coach/voices — the speakers voice_config.speaker accepts,
grouped by gender:
{
"results": {
"female": ["ritu", "priya", "neha", "pooja", "kavya", "shreya", "tanya", "shruti"],
"male": ["aditya", "rahul", "rohan", "amit", "varun", "kabir", "shubh", "tarun"]
}
}