API Reference
All endpoints require Authorization: Bearer <token>.
Table of contents
Characters
| Method | Path | Summary |
|---|---|---|
POST | /v1/characters | Create a new character |
GET | /v1/characters | List all characters for the tenant |
GET | /v1/characters/{id} | Get a character by ID |
PATCH | /v1/characters/{id}/profile | Update character profile (systemPrompt, personality, background, rules, customFields) |
PATCH | /v1/characters/{id}/agent-config | Update agent configuration (Developer+) |
POST | /v1/characters/{id}/clone | Clone a character for parallel agent instances (Developer+) |
PUT | /v1/characters/{id}/aliases | Set searchable aliases for the character |
POST | /v1/characters/{id}/archive | Archive a character |
GET | /v1/characters/resolve/{alias} | Resolve a character by alias |
GET | /v1/characters/{id}/export | Export character memories as Markdown |
Create character
Request body:
{
"name": "My Agent",
"categoryPreset": "developer"
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name (must be unique within the tenant) |
categoryPreset | string | no | Memory category layout: developer, standard |
Response 201:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "My Agent",
"status": "ACTIVE",
"categoryPreset": "developer",
"createdAt": "2026-03-10T10:30:00Z"
}
List characters
GET /v1/characters
| Param | Type | Required | Description |
|---|---|---|---|
page | int | no | Page number, 0-based (default: 0) |
limit | int | no | Page size, max 100 (default: 20) |
tag | string | no | Filter by tag (e.g. client:acme) |
capability | string | no | Filter by agent capability (e.g. java) |
agentStatus | string | no | Filter by agent status: IDLE, BUSY, FAILED, PAUSED |
sortBy | string | no | CREATED_AT, LAST_MEMORY_AT, MEMORY_COUNT, NAME (default: CREATED_AT) |
sortOrder | string | no | ASC or DESC (default: DESC) |
Update agent config
PATCH /v1/characters/{id}/agent-config — Developer+ tier
Patch-style update: only provided fields are changed. Omitted fields keep their current value.
Request body:
{
"capabilities": ["java", "python", "code-review"],
"status": "IDLE",
"maxConcurrentTasks": 3,
"preferredModel": "claude-sonnet-4-6",
"ownerId": "orchestrator-1",
"meta": { "env": "production" }
}
| Field | Type | Required | Description |
|---|---|---|---|
capabilities | string[] | no | What this agent can do (used for routing) |
status | string | no | IDLE, BUSY, FAILED, PAUSED |
maxConcurrentTasks | int | no | Max parallel tasks, 1–10 |
preferredModel | string | no | AI model identifier |
ownerId | string | no | Orchestrator or owner identifier |
meta | object | no | Arbitrary key-value metadata |
Response 200: Full character object with updated profile.agentConfig.
Clone character
POST /v1/characters/{id}/clone — Developer+ tier
Creates a copy of a character with the source’s profile (including agent config, forced to IDLE). Useful for spawning parallel agent instances.
Request body:
{
"name": "My Agent (Worker 2)",
"externalId": "worker-2",
"copyTags": false,
"copyMemories": false
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | Display name for the clone (must be unique) |
externalId | string | no | External identifier for the clone |
copyTags | boolean | no | Copy tags from source (default: false) |
copyMemories | boolean | no | Copy memories from source (not yet available — returns 501) |
Response 201:
{
"character": { "id": "...", "name": "My Agent (Worker 2)", "..." },
"memoriesCopied": 0
}
Memories
| Method | Path | Summary |
|---|---|---|
POST | /v1/characters/{id}/memories | Add a memory (AI-extracted on paid tiers) |
POST | /v1/characters/{id}/memories/direct | Add a memory directly, bypassing AI extraction |
GET | /v1/characters/{id}/memories | List all memories |
GET | /v1/characters/{id}/memories/{memId} | Get a memory by ID |
PUT | /v1/characters/{id}/memories/{memId} | Update memory content |
DELETE | /v1/characters/{id}/memories/{memId} | Delete a memory |
POST | /v1/characters/{id}/memories/search | Semantic search across memories |
GET | /v1/characters/{id}/memories/{memId}/history | Get revision history for a memory |
Add memory
Request body:
{
"content": "User prefers dark mode and vim keybindings",
"category": "preferences",
"importance": "NORMAL"
}
| Field | Type | Required | Description |
|---|---|---|---|
content | string | yes | The memory text (max 10,000 chars) |
category | string | no | Override auto-detected category |
importance | string | no | CRITICAL, HIGH, NORMAL, LOW (default: NORMAL) |
Search memories
Request body:
{
"query": "UI preferences",
"limit": 10,
"category": "preferences"
}
| Field | Type | Required | Description |
|---|---|---|---|
query | string | yes | Natural language search query |
limit | int | no | Max results (default: 10, max: 100) |
category | string | no | Filter to a specific category |
Categories
| Method | Path | Summary |
|---|---|---|
POST | /v1/characters/{id}/categories | Add a custom memory category |
PUT | /v1/characters/{id}/categories/{name} | Update category description, importance, or hints |
DELETE | /v1/characters/{id}/categories/{name}?reassign_to=... | Remove a category (reassign its memories) |
File Sync
| Method | Path | Summary |
|---|---|---|
POST | /v1/characters/{id}/sync | Push a file snapshot for sync |
GET | /v1/characters/{id}/sync/status | Get sync status |
GET | /v1/files/{fileId} | Download a synced file |
GET | /v1/files | List synced files for a character |
POST | /v1/characters/{id}/import | Import and extract memories from a document |
Tier
| Method | Path | Summary |
|---|---|---|
GET | /v1/tier | Get tier info, feature flags, and current usage |
Response 200:
{
"tier": "DEVELOPER",
"features": {
"autoRecallAvailable": true,
"autoCaptureAvailable": true,
"aiExtractionAvailable": true,
"directWriteAvailable": true,
"importPipelineAvailable": true,
"teamSharingEnabled": true,
"minSyncIntervalSeconds": 15,
"maxRequestsPerMinute": 60,
"maxMembers": 3,
"maxApiKeys": 3,
"maxCharacters": 30,
"currentCharacterCount": 5
}
}
Error responses
All errors use a consistent envelope:
{
"error": {
"type": "CharacterNotFound",
"message": "Character not found: 550e8400-e29b-41d4-a716-446655440000",
"status": 404
}
}
Error type → HTTP status mapping
| Error Type | Status | Description |
|---|---|---|
CharacterNotFound | 404 | Character ID does not exist or is not visible |
MemoryNotFound | 404 | Memory ID does not exist |
FileNotFound | 404 | File ID does not exist |
InvalidContent | 400 | Memory content is empty or exceeds limit |
InvalidInput | 400 | Request field is missing or malformed |
DuplicateCharacterName | 400 | A character with this name already exists |
CategoryNotConfigured | 400 | Requested category not in character’s preset |
InvalidPreset | 400 | Unknown categoryPreset value |
VisibilityChangeNotAllowed | 400 | Cannot change character visibility in this state |
ValidationError | 400 | Bean validation failure (field-level errors) |
Unauthorized | 401 | Missing or invalid Bearer token |
AccessDenied | 403 | Token is valid but access is denied |
FeatureNotAvailable | 403 | Feature requires a higher tier |
InsufficientRole | 403 | Member role does not permit this operation |
TierLimitExceeded | 429 | Rate limit or AI ops quota exceeded |
CharacterLimitExceeded | 429 | Character count at tier maximum |
ConflictUnresolved | 409 | Concurrent write conflict |
SnapshotConflict | 409 | File sync snapshot version conflict |
ExtractionFailed | 502 | Upstream AI provider returned an error |
SyncFailed | 502 | File sync backend error |
InternalError | 500 | Unexpected server error |
Interactive docs
The interactive API reference renders the full OpenAPI 3.0 spec with request/response examples, schema types, and a built-in request builder.