API Reference
Every endpoint of the Neocortex Web API
The Neocortex Web API is a set of HTTP endpoints for talking to your characters programmatically. This reference covers all of them: chat, session history, speech, transcription, account, usage and characters.
Endpoints
All endpoints live under one base URL:
https://api.neocortex.link/v3| Method | Path | Description |
|---|---|---|
POST | /chat | Talk to one character or a whole cast. |
POST | /chat/session | Read a session transcript, paged. |
POST | /audio/generate | Speak a line in the character's voice. |
POST | /audio/transcribe | Turn speech into text. |
GET | /account | Plan, credits and next refresh. |
GET | /usage | Credit status and per player or per character usage. |
GET | /characters | List the characters your key can use. |
Using your API Key
With each request do not forget to send your API Key with the x-api-key header.
Headers x-api-key: YOUR_API_KEYKeys are created in the dashboard and are scoped to your team. Every character you reference must belong to that team.
Chat with a character
One endpoint for a single character and for a group. Pass one id in characterIds for normal chat, or up to five for a group scene.
POST https://api.neocortex.link/v3/chat{
"characterIds": ["cmrkiw4f100017k7sfnicq08e"], // Required, 1 to 5 characters
"message": "Hey there!", // The player's line. Omit for an ambient turn
"playerId": "player-001", // Optional, enables per player usage and limits
"sessionId": "", // Optional, continue an existing conversation
"speakerCharacterId": "", // Optional, force who answers this turn
"playAs": null, // Optional, a character the player role plays
"maxTurns": 5, // Optional, cap on speakers per turn (max 5)
"metadata": [], // Optional, what the character can perceive
"events": [] // Optional, recent world events
}{
"sessionId": "cmdruuvyr0000jr04lteh35te",
"messages": [
{
"characterId": "cmrkiw4f100017k7sfnicq08e",
"name": "Aria",
"lines": [
{ "text": "Good evening.", "emotion": "HAPPY" },
{ "text": "What can I get you tonight?", "emotion": "CURIOUS" }
],
"actions": [{ "name": "POUR_DRINK", "targetId": "tankard-1" }],
"flowState": ""
}
],
"metadata": []
}Response fields
| Field | Description |
|---|---|
sessionId | The conversation. Send it back to continue, store it per player. |
messages[] | One entry per character that spoke, in the order they spoke. |
messages[].characterId | Which character spoke this entry. |
messages[].name | The character's display name, handy for labelling a transcript. |
messages[].lines[] | The reply as 1 to 3 ordered chunks, each with its own emotion. |
messages[].actions[] | Actions triggered this turn, each { name, targetId }, in the order the character intends them. [] when none fired. |
messages[].flowState | The Conversation Flow checkpoint this turn landed on, empty when unused. |
metadata | The entities the characters perceived, echoed once for the scene, with isSubject marking whatever the actions targeted. |
Replies always come as lines
lines is the reply. The character splits it into 1 to 3 chunks so you can drop them in one after another and change expression or voice per line. Join every text for the complete reply.
See Interactables for metadata, events and how actions[].targetId works, and Group Chat for speakerCharacterId, playAs and casts.
Get past messages
Reads a transcript oldest first, scoped to your team.
POST https://api.neocortex.link/v3/chat/session{
"sessionId": "cmdruuvyr0000jr04lteh35te", // Required
"limit": 20, // Optional, 1 to 100, default 20
"before": "" // Optional, a previous nextCursor
}{
"sessionId": "cmdruuvyr0000jr04lteh35te",
"messages": [
{
"content": "Hey there!",
"sender": "USER",
"speakerCharacterId": null,
"name": null,
"addressedTo": null,
"emotion": null,
"actions": [],
"createdAt": "2026-07-18T10:00:00.000Z"
},
{
"content": "Good evening. What can I get you tonight?",
"sender": "ASSISTANT",
"speakerCharacterId": "cmrkiw4f100017k7sfnicq08e",
"name": "Aria",
"addressedTo": "Player",
"emotion": "HAPPY",
"actions": ["POUR_DRINK"],
"createdAt": "2026-07-18T10:00:02.000Z"
}
],
"nextCursor": "cmdruv1c40002jr04a1b2c3d4"
}To page backwards through older messages, send the previous response's nextCursor as before. It is null once you reach the start of the conversation.
name and addressedTo are what make a group transcript readable: who spoke, and who they were speaking to.
Generate speech
Speaks a line in the character's configured voice. The character needs a Voice node, otherwise this returns 403 or 404.
POST https://api.neocortex.link/v3/audio/generate{
"characterId": "cmrkiw4f100017k7sfnicq08e", // Required
"message": "Good evening, traveller.", // Required
"emotion": "HAPPY", // Optional, colours the delivery
"format": "wav" // Optional, audio format
}Raw audio bytes.
This endpoint does not return JSON on success. Write the body straight to a
file or feed it to your audio player.The character's Language node decides the spoken language automatically.
Transcribe audio
Send multipart/form-data, not JSON.
POST https://api.neocortex.link/v3/audio/transcribe| Field | Type | Description |
|---|---|---|
characterId | text | Required. Its Language node picks the transcription language. |
audio | file | Required. The recorded clip, for example a .wav. |
curl -X POST https://api.neocortex.link/v3/audio/transcribe \
-H "x-api-key: YOUR_API_KEY" \
-F "characterId=cmrkiw4f100017k7sfnicq08e" \
-F "audio=@recording.wav"{ "response": "Hey, who are you and where am I?" }Get account status
GET https://api.neocortex.link/v3/account{
"tier": "PRO",
"email": "you@studio.com",
"creditsRemaining": 8420,
"nextRefresh": "2026-08-01T00:00:00.000Z"
}nextRefresh is null when nothing is scheduled to refresh.
Get usage
Both query parameters are optional. Pass playerId to get that player's row, characterId to get that character's row.
GET https://api.neocortex.link/v3/usage?playerId=player-001&characterId=cmrkiw4f100017k7sfnicq08e{
"status": "ok",
"creditsRemaining": 8420,
"player": {
"interactionsToday": 3,
"creditsUsedAllTime": 47,
"overLimit": false
},
"character": {
"creditsUsedAllTime": 128,
"overLimit": false
}
}status is ok, low or empty. overLimit reflects the per player and per character caps you configure in the dashboard. An unknown player returns zero usage rather than an error, so you can gate on it safely.
List characters
GET https://api.neocortex.link/v3/characters{
"characters": [
{ "id": "cmrkiw4f100017k7sfnicq08e", "name": "Aria" },
{ "id": "cmrkiwj2k00037k7sxnpvs9p3", "name": "Bram" }
]
}Id and name only. Useful for building a character picker in your own tooling.
Errors
Failures return { "error": "..." } with an HTTP status:
| Status | Meaning |
|---|---|
401 | Missing or invalid API key. |
403 | The character does not belong to your key's team, or your plan does not allow it (a cast of more than one character needs Pro or Team). |
404 | Character, session or voice not found. |
422 | The request is malformed: empty message, more than 5 characters, a speakerCharacterId that is not in the cast, a playAs that is also in the cast, or an input over its size limit. |
429 | Daily allowance for dashboard and editor calls exhausted. |
400 | Out of credits. |