API Reference

REST endpoints for the Soullayer Cloud and self-hosted API. All responses are JSON.

Authentication

Endpoints authenticate via session cookies (browser) or Bearer token / API key (sk_sl_..., for CLIs and agents). All non-GET requests also require an X-CSRF-Token header when using cookie auth.

# All API calls require a Bearer token
curl -H "Authorization: Bearer YOUR_TOKEN" \
  https://api.soullayer.ai/v1/identity

# Self-hosted (default port 4747)
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://127.0.0.1:4747/v1/identity

Identity & State

# Get the current Identity Pack
GET /v1/identity
  → 200 { "identity": { "name": "...", "bio": "...", "style": {...} } }

# Update identity (merges into existing pack)
PATCH /v1/identity
Content-Type: application/json
  { "identity": { "bio": "New bio" } }
  → 200 { "updated": true, "version": 42 }

# Get preferences
GET /v1/preferences
  → 200 { "preferences": {...} }

# Get current state (short-lived facts)
GET /v1/state
  → 200 { "state": {...} }

Compilation

Compile your SSD into platform-native formats. Registered targets: openai, claude, cursor, langchain, openclaw, ollama, plaintext.

# Compile identity for a target platform
GET /v1/compile?target=openai
GET /v1/compile?target=claude
GET /v1/compile?target=cursor
GET /v1/compile?target=langchain
GET /v1/compile?target=ollama
GET /v1/compile?target=plaintext
  → 200 { "output": "...", "truncated": false, "target": "openai" }

# If encryption is enabled and the SSD is locked:
  → 409 { "error": { "code": "E2E_ENCRYPTED", "message": "Unlock your profile at app.soullayer.ai" } }

Policy

The policy pack is a set of rules evaluated against any value passing through the compiler. See Policy Grammar for rule structure.

# Get the active policy rules
GET /v1/policy
  → 200 { "rules": [...] }

# Replace the policy pack
PUT /v1/policy
  { "rules": [{ "id": "r1", "description": "Redact email", "condition": {...}, "action": "redact" }] }
  → 200 { "accepted": true }

# Evaluate a value against current policies
POST /v1/policy/eval
  { "value": "My email is alice@example.com" }
  → 200 { "allowed": true, "redactions": [...], "violations": [] }

Versions

Every mutation to the SSD produces a new version. Snapshots every 50 versions, JSON Patch deltas between them.

# List versions (reverse chronological)
GET /v1/versions?limit=20
  → 200 { "versions": [{ "id": 42, "createdAt": "...", "summary": "..." }], "total": 127 }

# Get a specific version
GET /v1/versions/:id
  → 200 { "id": 42, "ssd": {...} }

# Diff two versions
GET /v1/versions/:from/diff/:to
  → 200 { "operations": [{ "op": "replace", "path": "/identity/bio", "value": "..." }] }

# Rollback to a prior version
POST /v1/versions/:id/rollback
  → 200 { "rolledBackTo": 41 }

Adaptation

LLM-powered learning from conversation transcripts. Proposals are JSON Merge Patches you approve or reject.

# Ingest a transcript (LLM-powered proposals)
POST /v1/adapt/ingest
  { "transcript": "USER: ...\nASSISTANT: ...", "source": "manual" }
  → 200 { "proposals": [{...}] }
  → 429 {
      "error": { "code": "RATE_LIMIT_EXCEEDED", "message": "..." },
      "resetsAt": "2026-04-17T00:00:00.000Z",
      "dailyLimit": 10, "todayCount": 10
    }

# List proposals
GET /v1/adapt/proposals?status=pending&limit=20
GET /v1/adapt/proposals?limit=50

# Approve / reject
POST /v1/adapt/proposals/:id/approve
POST /v1/adapt/proposals/:id/reject

# Auto-approve all pending above a confidence threshold
POST /v1/adapt/auto-approve
  { "threshold": 0.85 }
  → 200 { "approved": 3, "proposals": [...] }

# Stats (includes daily quota)
GET /v1/adapt/stats
  → 200 {
      "total": 42, "pending": 3, "approved": 30, "rejected": 6, "autoApproved": 3,
      "quota": { "todayCount": 5, "dailyLimit": 10, "remaining": 5, "resetsAt": "..." }
    }

MCP

Per-user Model Context Protocol server. SSE transport authenticated with an API key. See MCP Setup.

# Open an SSE MCP session (API-key auth)
GET /v1/mcp/sse
Authorization: Bearer sk_sl_...
  → event stream

# Management (cookie-auth, dashboard-only)
GET /v1/mcp/connections
  → 200 { "connections": [{ "id": "...", "connectedAt": "..." }], "limit": 3, "plan": "pro" }

DELETE /v1/mcp/connections/:id
  → 200 { "disconnected": true }

Encryption

End-to-end encryption is optional (Pro+). The browser derives a 256-bit key via Argon2id and encrypts the SSD with AES-256-GCM. The server only ever stores ciphertext, a salt, and a verify-hash.

# Get encryption status
GET /v1/encryption/status
  → 200 { "enabled": true, "salt": "...", "recoveryConfigured": true }

# Enable encryption (client derives key, encrypts, sends ciphertext only)
POST /v1/encryption/enable
  {
    "encryptedSSD": "...",
    "salt": "...",
    "verifyHash": "...",
    "recovery": { "salt": "...", "verifyHash": "...", "wrappedSSD": "..." }
  }

# Change passphrase (client re-encrypts)
POST /v1/encryption/change-passphrase
  { "reEncryptedSSD": "...", "newSalt": "...", "newVerifyHash": "..." }

# Recovery flow (lost passphrase, using 24-word mnemonic)
GET /v1/encryption/recovery/info     → { salt, verifyHash }
POST /v1/encryption/recovery/unwrap  { verifyHash } → { wrappedSSD }
POST /v1/encryption/recovery/rotate  { salt, verifyHash, wrappedSSD } → { rotated: true }

# Disable (requires client-decrypted SSD)
POST /v1/encryption/disable
  { "decryptedSSD": {...} }

API Keys

API keys are hashed with SHA-256 on storage. The raw key is returned once at creation and cannot be retrieved later.

# List API keys (metadata only — raw key only returned once on creation)
GET /v1/api-keys
  → 200 { "keys": [{ "id", "name", "prefix", "scopes", "lastUsedAt", "createdAt" }] }

# Create a new key
POST /v1/api-keys
  { "name": "Cursor IDE", "scopes": ["mcp", "compile"] }
  → 201 { "id": "...", "key": "sk_sl_...", "prefix": "sk_sl_abc" }

# Revoke
DELETE /v1/api-keys/:id

Auth lifecycle

# Authentication endpoints
POST /v1/auth/register    { email, password, name }
POST /v1/auth/login       { email, password } → sets sl_access/sl_refresh cookies
POST /v1/auth/logout
POST /v1/auth/refresh     → rotates session
POST /v1/auth/resend-verification { email }
DELETE /v1/auth/account   { password, confirmation } → schedules deletion (30d grace)
POST /v1/auth/account/cancel-deletion
GET /v1/auth/export       → GDPR Article 20 data bundle (JSON download)
GET /v1/auth/csrf-token   → issues X-CSRF-Token for non-GET requests

Error codes

All error responses use { "error": { "code": "...", "message": "..." } }.

AUTH_REQUIRED          401   Missing or invalid session / API key
VALIDATION_FAILED      400   Request body failed schema validation
FORBIDDEN              403   Valid credentials, insufficient permissions
NOT_FOUND              404   Resource does not exist
CONFLICT               409   State conflict (e.g., already enabled)
E2E_ENCRYPTED          409   SSD is locked client-side, unlock required
RATE_LIMIT_EXCEEDED    429   Plan quota exhausted (see resetsAt)
CONNECTION_LIMIT       429   Too many concurrent MCP sessions
PLAN_LIMIT_EXCEEDED    403   Feature gated behind higher plan
DUPLICATE_TRANSCRIPT   409   Transcript SHA-256 hash already processed
INTERNAL_ERROR         500   Unexpected server error (check logs)