API Reference
The Ensoul API lets you create personas, talk to them on behalf of your own end users, place them in worlds, ask many personas at once, and run simulations.
API access requires authentication via API key or OAuth. See the SDKs page for official client libraries.
The hosted API base URL is https://api.ensoul-ai.com. All endpoint paths below are versioned under /v1 (for example, https://api.ensoul-ai.com/v1/personas).
Authentication
Ensoul supports two authentication methods:
Google OAuth (UI)
API Keys (Programmatic)
Using API Keys
Pass your API key in the X-API-Key header (OAuth users send a JWT in the Authorization: Bearer header instead):
curl -X GET "https://api.ensoul-ai.com/v1/api/me" \-H "X-API-Key: YOUR_API_KEY"
/v1/api/meYour plan's current limits, and the key you used. key.kind is full for a team key, or persona for a key bound to one persona, with key.persona_id naming it.
{"tier": "...","personas": { "...": "..." },"domains": { "...": "..." },"credits": { "...": "..." },"key": { "kind": "persona", "persona_id": "PERSONA_UUID" }}
Security
Hello World
Create a persona with no world, send it one message as one of your end users, and end the conversation.
# pip install ensoul
from ensoul import Ensoul
client = Ensoul(api_key="YOUR_API_KEY")
# A persona needs no world. This one stands alone.
persona = client.personas.create(name="Ada")
# user_id is your own id for the person talking.
# Each end user gets their own conversations with the persona.
reply = client.chat.send(
persona.id,
"Hi! Who are you?",
user_id="YOUR_END_USER_ID",
)
print(reply.response)
# End the conversation when the person is done.
client.chat.end_conversation(
persona.id,
reply.conversation_id,
user_id="YOUR_END_USER_ID",
)Personas
Create and manage personas. Only a name is required: a persona created with no domain in the body has no world.
/v1/personasList personas with pagination and filters (region, archetype, country, city).
/v1/personasCreate a persona. Add a world name as domain to place it in that world.
/v1/personas/batchCreate multiple personas at once with controlled distribution.
/v1/personas/:idGet a specific persona with full trait profile.
/v1/personas/:id/personalityGet a persona's full personality vector.
Chat
1:1 conversations with individual personas, on behalf of your own end users. Every response is generated through real-time inference.
/v1/personas/:id/chatSend a message to a persona and receive a response.
{"message": "What do you think about remote work?","user_id": "YOUR_END_USER_ID","conversation_id": "optional-conversation-uuid"}
/v1/personas/:id/chat/streamStream a persona's response token-by-token via Server-Sent Events.
/v1/personas/:id/conversationsList a persona's conversations.
/v1/personas/:id/conversations/:conversationIdGet one conversation with its messages.
/v1/personas/:id/conversations/:conversationId/endEnd a conversation. The persona files what it learned, and a later turn on it gets 409 conversation_ended. Returns 204 with no body.
{"user_id": "YOUR_END_USER_ID","reason": "done"}
/v1/personas/:id/conversations/:conversationIdDelete a stored conversation. The persona's memories stay.
/v1/chat/sessionsList chat sessions.
/v1/chat/sessions/:idGet a specific chat session with message history.
End Users
user_id is your own id for the person talking. Each end user gets their own conversations with a persona. Send the same user_id to chat, end and delete a conversation.
A key bound to one persona must send user_id on every conversation route, or the API answers 400 with user_id_required.
/v1/end-users/forgetErase everything kept for one end user: their conversations and messages, and the memories personas formed from them.
{"user_id": "YOUR_END_USER_ID"}
{"user_id": "YOUR_END_USER_ID","conversations_erased": 3,"memories_erased": 12}
Full keys only
key_scope. A later turn as a forgotten end user gets 409 with end_user_forgotten.Worlds
A world holds knowledge and relationships its personas share. A persona does not need one. The API calls a world a domain, so its paths and fields say domain.
/v1/domainsList the worlds your account can reach.
/v1/domainsCreate a world (Studio has a guided wizard).
/v1/domains/:nameGet one world by name with its full configuration.
/v1/domains/generateGenerate a complete world from a text description.
/v1/domains/:id/personas/batch/streamGrow a world's population from its archetypes and tiers, streaming each persona as they are made.
Residency
A persona lives in at most one world at a time, and moving keeps everything it has: its traits, memories and relationships go with it. A persona that already lives in a world is taken out of it before it can be brought into another.
/v1/personas/:id/place-in-worldBring a persona into a world. It keeps everything it has, including whatever archetype and tier values it last had.
/v1/personas/:id/remove-from-worldTake a persona out of its world. It keeps its memories and relationships and lives on its own.
/v1/personas/:id/worldsEvery world a persona has lived in, newest first.
Networks
A network is a named set of personas who know each other. It belongs to your team, spans worlds, and can hold personas who live in none.
/v1/networksList your team's networks.
/v1/networksCreate a network.
/v1/networks/:idGet one network with its members.
/v1/networks/:idRename a network or change its description.
/v1/networks/:idDelete a network. Its personas and the ties between them are kept.
/v1/networks/:id/membersAdd personas to a network.
/v1/networks/:id/members/:personaIdTake one persona out of a network.
/v1/networks/:id/graphThe network's personas and the ties between them.
Ask Many Personas
Ask many personas the same question at once and read their answers together.
/v1/aggregate/streamStream answers from many personas.
/v1/aggregate/stream/groupedStream grouped aggregate results (by archetype or tier).
/v1/aggregate/countCount the personas your filters match.
Simulations
Run multi-step simulations where personas interact and evolve over time.
/v1/simulationsList all simulations.
/v1/simulationsCreate a simulation. Its personas come from one source: a world (domain_id), a network (network_id), or a list you name.
/v1/simulations/:idGet simulation details and status.
/v1/simulations/:id/startStart a simulation.
/v1/simulations/:id/pausePause a running simulation.
/v1/simulations/:id/speedAdjust simulation speed.
/v1/simulations/:id/streamStream real-time simulation events (SSE).
/v1/simulations/:id/historyGet simulation interaction history.
/v1/simulations/:id/checkpointsList simulation checkpoints.
/v1/simulations/:id/checkpoints/:cpId/restoreRestore simulation to a checkpoint.
Persona Memories
Manage persona long-term memories and batch memory generation.
/v1/memory/:personaIdList memories for a persona.
/v1/memory/:personaId/generateGenerate memories for a persona (using bloom modes).
/v1/memory/:personaId/batchBatch create memories.
/v1/memory/:personaId/:memoryIdDelete a specific memory.
/v1/domains/:id/memories/generate-batchBatch generate memories for every persona in a world.
/v1/domains/:id/memories/bloom-jobsList bloom (memory generation) jobs.
/v1/domains/:id/memories/bloom-jobs/:jobId/cancelCancel a running bloom job.
Frameworks & Validation
Manage personality frameworks and run validation experiments.
/v1/frameworksList available personality frameworks.
/v1/frameworks/:idGet framework details including traits and grounding.
/v1/frameworks/:id/traits/:traitName/groundingGet/update trait grounding text.
/v1/frameworks/:id/auto-tuneAI-generate improved trait grounding.
/v1/validationsList validation runs.
/v1/validationsStart a new validation experiment.
/v1/validations/:idGet validation results.
/v1/validations/:id/tuning-reportGet auto-tune report for a validation.
Error Handling
The API uses standard HTTP status codes. The body is a flat JSON object with a request_id. On a typed refusal error is the code, with its fields beside it. On a plain HTTP error error names the status and message explains it.
{"error": "conversation_ended","conversation_id": "conversation-uuid","request_id": "req_abc123"}
Status Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request: invalid parameters, or user_id_required when a key bound to one persona sends no user_id |
| 401 | Unauthorized: invalid or missing credentials |
| 403 | Forbidden: insufficient permissions, or key_scope when a key bound to one persona calls a team-only route |
| 402 | Payment Required: a monthly limit is reached, such as a persona's calls this month (persona_calls) |
| 404 | Not Found: the resource doesn't exist |
| 409 | Conflict: turn_in_flight, conversation_ended or end_user_forgotten |
| 429 | Rate Limited: too many requests |
| 500 | Server Error: something went wrong |
Rate Limits
Rate limits and monthly limits depend on your plan. GET /v1/api/me returns your current limits. A request over the rate limit gets 429.