API Documentation

Quick Start

Get an NPC talking in under 60 seconds:

# Install CLI
npm install -g ainpc-cli
# Login (get key at /auth/register)
ainpc login --key YOUR_KEY --game my-rpg
# Create an NPC
ainpc create "Grok" --role merchant --traits gruff,honest
# Talk to them
ainpc say NPC_ID "Got any swords?"
# Hmph. A strong blade takes strong coin, stranger.
# AI-generate a full NPC
ainpc generate --role guard --name "Captain Voss"
# NPC voice
ainpc speak NPC_ID "Welcome to my forge"

Or use MCP for Claude Code native integration: ainpc mcp-serve | View on npm

Authentication

CLI (recommended): Headers are automatic after login.

ainpc login --key YOUR_KEY --game my-rpg
# All subsequent commands auto-include credentials

REST API (direct): Two headers required on every request:

HeaderDescription
x-api-keyYour API key
x-game-idYour game identifier (tenant isolation)

Create NPC

POST /api/npcs

{
  "name": "Grok the Blacksmith",
  "role": "merchant",
  "faction": "village_guard",
  "location": "blacksmith_shop",
  "personality": {
    "traits": ["gruff", "honest", "protective"],
    "speechStyle": "gruff",
    "backstory": "Former soldier who retired to smithing",
    "values": ["honor", "craft", "family"],
    "quirks": ["always mentions the weather"]
  },
  "inventory": [
    { "item": "iron_sword", "price": 50, "quantity": 2 },
    { "item": "shield", "price": 30, "quantity": 1 }
  ]
}

Send Event

POST /api/npcs/:npcId/event

{
  "type": "player_dialogue",
  "playerId": "player_joe",
  "message": "Do you have any swords for sale?",
  "context": {
    "location": "blacksmith_shop",
    "timeOfDay": "morning",
    "weather": "sunny",
    "playerReputation": 75,
    "playerLevel": 12
  }
}

Response:

{
  "response": {
    "dialogue": "Aye lad, got a fine iron blade. Fifty gold.",
    "emotion": "cheerful",
    "action": { "type": "gesture", "target": "display_rack" },
    "tradeOffer": { "item": "iron_sword", "price": 45 },
    "memoryUpdated": true
  },
  "tokenUsage": { "input": 1200, "output": 85, "calls": 1 }
}

Errors: unknown npcId returns 404 { "error": "NPC not found" }. If experts are unavailable or all fail, the response includes an error field ({ "code": "no_experts" | "experts_failed", "message": "..." }) alongside a fallback response — check it to distinguish an outage from a quiet NPC.

WebSocket

Connect to ws://host:port/ws?apiKey=xxx&gameId=yyy

Send events:

{ "action": "event", "data": { "type": "player_dialogue", "npcId": "...", "message": "...", "context": {...} } }
{ "action": "subscribe", "npcIds": ["npc1", "npc2"] }

Update NPC

PATCH /api/npcs/:npcId — Update any NPC properties (partial update).

curl -X PATCH http://localhost:18542/api/npcs/{npcId} \
  -H "x-api-key: your-key" \
  -H "x-game-id: my-game" \
  -H "Content-Type: application/json" \
  -d '{"location": "town_square", "mood": {"emotion": "angry", "intensity": 0.8, "cause": "theft"}}'

Generate NPC

POST /api/npcs/generate — AI-generate an NPC with full persona, psychology, and schedule.

curl -X POST http://localhost:18542/api/npcs/generate \
  -H "x-api-key: your-key" \
  -H "x-game-id: my-game" \
  -H "Content-Type: application/json" \
  -d '{"role": "merchant", "name": "Grok"}'

Returns a full NPC with cognitive extensions: persona (OCEAN personality, backstory, fears, ambitions), schedule (daily routines), and psychology (stress, trauma, goals, emotions).

Batch Generate

POST /api/npcs/generate-batch — Generate multiple NPCs with social relationships.

curl -X POST http://localhost:18542/api/npcs/generate-batch \
  -H "x-api-key: your-key" \
  -H "x-game-id: my-game" \
  -H "Content-Type: application/json" \
  -d '{"count": 5, "role": "guard"}'

Returns { npcs: [...], socialLinks: [...] } — NPCs plus auto-generated relationships between them.

Batch Events

POST /api/events — Send multiple events in one request.

{
  "events": [
    { "type": "player_dialogue", "npcId": "npc1", "playerId": "p1", "message": "Hello!", "context": {...} },
    { "type": "player_approached", "npcId": "npc2", "playerId": "p1", "context": {...} }
  ]
}

Returns { results: [EventResult, ...] } — one result per event, in order. Batch results are always 200; per-event failures (e.g. unknown npcId) are flagged via the result's error field ({ "code": "npc_not_found", ... }).

Unity SDK

Copy sdk/unity/ into Assets/Plugins/AINPCEngine/

var client = new NPCEngineClient("http://localhost:18542", "key", "my-game");

// Talk to an NPC
var result = await client.Say(npcId, "player1", "Hello!", context);
Debug.Log(result.response.dialogue);

// AI-generate an NPC with full persona
var npc = await client.GenerateNPC(new GenerateNPCRequest { role = "merchant" });

// Batch-generate NPCs with relationships
var batch = await client.GenerateBatch(new GenerateBatchRequest { count = 5, role = "guard" });

// Send batch events
var results = await client.SendBatchEvents(new BatchEventItem[] { ... });
Quick Start Demo — Clone and play a working village with 3 AI NPCs in under 5 minutes:
git clone https://github.com/jyswee/ainpc-unity-demo.git View on GitHub

Unreal SDK

Copy sdk/unreal/AINPCEngine/ into your project's Plugins/ folder and enable in the Plugin Manager.

// Create client
UNPCEngineClient* Client = NewObject<UNPCEngineClient>();
Client->Init("http://localhost:18542", "key", "my-game");

// Bind response delegate
Client->OnEventResult.AddDynamic(this, &AMyActor::OnNPCResponse);

// Talk to an NPC
FGameContext Context;
Context.Location = "blacksmith_shop";
Context.TimeOfDay = "morning";
Client->Say(NpcId, "player1", "Got any swords?", Context);

// AI-generate an NPC
FGenerateNPCRequest GenReq;
GenReq.Role = "merchant";
Client->GenerateNPC(GenReq);

Full Blueprint support — all methods are BlueprintCallable and responses fire BlueprintAssignable delegates.

Quick Start Demo — Clone and play a working village with 3 AI NPCs in UE5:
git clone https://github.com/jyswee/ainpc-unreal-demo.git View on GitHub

Godot SDK

Copy sdk/godot/addons/ainpcengine/ into your project's addons/ folder. Enable in Project → Project Settings → Plugins.

var client = AINPCEngineClient.new()
client.setup("http://localhost:18542", "key", "my-game")
add_child(client)

# Talk to an NPC
var context = AINPCModels.game_context("blacksmith", "morning", "sunny")
var result = await client.say(npc_id, "player1", "Got any swords?", context)
print(result.response.dialogue)

# AI-generate an NPC
var npc = await client.generate_npc("merchant", "Grok")

# Batch-generate NPCs with relationships
var batch = await client.generate_batch(5, "guard")

Uses Godot 4 await pattern. WebSocket client available via AINPCWebSocket class for real-time streaming.

Quick Start Demo — Clone and play a working village with 3 AI NPCs in Godot 4:
git clone https://github.com/jyswee/ainpc-godot-demo.git View on GitHub

Rust SDK

Add to your Cargo.toml:

[dependencies]
ainpc-sdk = { git = "https://github.com/jyswee/ainpc-rust-sdk.git" }
use ainpc_sdk::{AINPCClient, GameContext};

#[tokio::main]
async fn main() {
    let client = AINPCClient::new("http://localhost:18542", "key", "my-game");

    // Talk to an NPC
    let result = client.say("npc_1", "player_1", "Hello!", GameContext {
        location: Some("village".into()),
        time_of_day: Some("morning".into()),
        weather: Some("sunny".into()),
        player_reputation: 75,
        player_level: 5,
        ..Default::default()
    }).await.unwrap();

    println!("NPC: {}", result.response.dialogue.unwrap_or_default());
}

Full REST client + WebSocket support. WASM-compatible (gate WebSocket behind native feature).

GitHub - git clone https://github.com/jyswee/ainpc-rust-sdk.git View on GitHub

Node.js / REST API

No SDK needed - use any HTTP client. All endpoints accept JSON with x-api-key and x-game-id headers.

const API = "https://ainpcengine.com/api";
const HEADERS = {
  "Content-Type": "application/json",
  "x-api-key": "your-api-key",
  "x-game-id": "my-game"
};

// Create an NPC
const npc = await fetch(`${API}/npcs`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({
    name: "Grok", role: "blacksmith",
    personality: {
      traits: ["gruff", "loyal"],
      speechStyle: "blunt, short sentences",
      backstory: "Third-gen smith",
      values: ["craftsmanship", "honor"],
      quirks: []
    }
  })
}).then(r => r.json());

// Talk to the NPC
const result = await fetch(`${API}/npcs/${npc.id}/event`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({
    type: "player_dialogue",
    playerId: "player_1",
    message: "Got any swords?",
    context: { location: "forge", timeOfDay: "morning" }
  })
}).then(r => r.json());

console.log(result.response.dialogue);

Works with Node.js, Python, Go, or any language with HTTP support. See Agent Quickstarts for AI coding agent integration.

CLI (npm)

Command-line interface for coding agents and quick testing. Zero dependencies.

npm install -g ainpc-cli

# Setup
ainpc login --key YOUR_KEY --game my-rpg

# Create NPC
ainpc create "Grok" --role merchant --traits gruff,loyal

# Talk to NPC
ainpc say NPC_ID "Got any swords?"

# AI-generate full NPC (NPC Persona)
ainpc generate --role guard

# List all NPCs
ainpc list

# NPC voice synthesis
ainpc speak NPC_ID "Welcome, traveler"

# Full reference
ainpc --help

Config stored in .ainpc/config.json (project-local) or ~/.ainpc/config.json (global). Supports --json flag for machine-readable output.

Agent Integration - Add to your CLAUDE.md, .cursorrules, or .clinerules:
Use the ainpc CLI for NPC management. Config auto-loaded from .ainpc/config.json or AINPC_API_KEY env. View on npm

Event Types

EventExpertsUse When
player_approachedDialogue + SocialPlayer enters NPC range
player_dialogueDialoguePlayer speaks to NPC
combat_startedCombat + DialogueFight begins
trade_requestedTrade + DialoguePlayer wants to buy/sell
quest_acceptedQuest + DialoguePlayer takes a quest
quest_completedQuest + Social + DialoguePlayer finishes quest
ambient_triggerAmbientIdle/background behavior
world_eventAmbient + SocialWeather change, explosion, etc.
npc_interactionSocial + DialogueNPC-to-NPC interaction
<custom>DialogueAny custom type string (e.g. bigHand, blunder) — routes to the Dialogue expert and stays in-character
Binding persona to the moment — pass these on context to make the NPC react in-character to a specific beat on any event type:
  • context.situation — what is happening right now, in plain text (e.g. "Joe just made a slam on 6S — react big"). This anchors the scene.
  • context.style — a per-event voice/style directive that reinforces the seeded personality (e.g. "ALL-CAPS machine voice; arcade card game, never mention fantasy").
  • context.playerName — display name to address the player by (playerId stays the stable memory key).
  • context.language — per-event output language as a BCP-47 tag (e.g. "en", "vi", "pt-BR"). Omit and the NPC infers its own language from the persona; set it and the NPC is hard-pinned to that language for this event. The same NPC can speak its native language on one surface and English on another without forking its memory.
Tear down pilot NPCs — don't promote them. NPC memory is persistent and scoped per NPC. If you test with real members and then reuse those NPCs in production, they will permanently "remember" the fictional test conversations. Before a real seed, DELETE your pilot NPCs and re-create them, rather than promoting the ones you tested with.