Skip to content

Twin Brain ​

Read-model endpoints for the AI Twin Brain Simulator: your twin's neural map (neurons, synapses, regions), its wiki-style memory graph, live activity, and an optional wallet-billed AI narration.

All graph data is computed server-side from what your twin has already learned. These endpoints never modify the twin.

Endpoints ​

MethodPathDescriptionAuth
GET/agents/twins/resolveResolve a subject to its twinJWT + Entitlement
GET/agents/twins/{twinId}/brain/graphBrain graph (nodes, edges, clusters, overlay)JWT + Entitlement
GET/agents/twins/{twinId}/brain/memory-graphWiki-style memory graphJWT + Entitlement
GET/agents/twins/{twinId}/brain/memories/{memoryId}Memory detail with provenance and evidenceJWT + Entitlement
GET/agents/twins/{twinId}/brain/activityLive activity levels for the brainJWT + Entitlement
GET/agents/twins/{twinId}/brain/chain-impact/{chainId}How a chain has shaped the brainJWT + Entitlement
POST/agents/twins/{twinId}/brain/sampleConsume the one-time free brain previewJWT + Entitlement
GET/agents/twins/{twinId}/brain/sample-statusWhether the one-time preview is still availableJWT + Entitlement
POST/agents/twins/{twinId}/brain/narrateAI narration of a brain region (wallet-billed)JWT + Entitlement
GET/public/twins/{username}/brainPublic brain showcase (opt-in only)None (30/min)

Plan access ​

FeatureEndpointsFreePlusProPro (higher capacity)
Brain Simulator (ai.twin.brain_simulator)resolve, graph, activity, chain-impact—✓✓✓
Memory Graph (ai.twin.memory_graph)memory-graph, memories/—✓✓✓
One-time preview (ai.twin.brain_sample)sample, sample-status✓ (once)———
AI Narration (ai.twin.brain_narrate)narrate—5/day25/day100/day

Calling an endpoint your plan does not include returns 403 with a message naming the missing feature key. See the feature guide for the full plan matrix.


GET /agents/twins/resolve ​

Description ​

Resolves a subject (you, a workspace, a team, or an agent) to its twin so you can call the brain endpoints. Twins are system-managed — this is how you discover the twinId.

Request ​

  • Headers: Authorization: Bearer <token>
  • Query params:
ParameterTypeRequiredDescription
subjectTypestringYesOne of chainer, workspace, team, agent
subjectIdstring (max 64)YesEntity id, or me when subjectType=chainer

You can only resolve your own personal twin, and twins that belong to your account (workspace twins additionally require membership in that workspace). Anything else returns 404.

Response ​

  • 200 OK
    json
    {
      "data": {
        "twinId": "3f7c2a90-5b1e-4d2a-8c4e-1a9d6b3f5e72",
        "name": "My Twin",
        "scopeKind": "chainer",
        "lifecycleState": "active"
      }
    }

Code Example ​

bash
curl "https://api.chainabit.com/api/v1/agents/twins/resolve?subjectType=chainer&subjectId=me" \
  -H "Authorization: Bearer $TOKEN"

GET /agents/twins/{twinId}/brain/graph ​

Description ​

Returns the strongest window of your twin's brain graph: neurons (nodes), synapses (edges), kind clusters, and optionally a productivity overlay that maps your chainies to regions and your chains to synapses. The strongest connections are returned first; truncated tells you when the full brain is larger than the returned window.

Request ​

  • Headers: Authorization: Bearer <token>
  • Path params: twinId (UUID)
  • Query params:
ParameterTypeRequiredDescription
maxNodesintegerNoNode budget. Default 150, maximum 300 (higher values are clamped)
kindsstring (CSV)NoNode kinds to include: topic, person, tool, trait, memory — e.g. kinds=topic,tool
overlaystringNoproductivity to include the regions/synapses overlay

Response ​

  • 200 OK
    json
    {
      "data": {
        "nodes": [
          { "id": "n-typescript", "kind": "topic", "label": "TypeScript", "weight": 4.6, "degree": 2, "lastSeen": "2026-06-10T09:12:41.000Z" },
          { "id": "n-testing", "kind": "topic", "label": "Testing", "weight": 2.9, "degree": 1, "lastSeen": "2026-06-09T18:02:10.000Z" },
          { "id": "n-deep-focus", "kind": "trait", "label": "Deep focus", "weight": 1.7, "degree": 1, "lastSeen": "2026-06-08T07:45:00.000Z" }
        ],
        "edges": [
          { "src": "n-typescript", "dst": "n-testing", "weight": 2.9, "releaseProb": 0.74, "sourceCount": 12 },
          { "src": "n-typescript", "dst": "n-deep-focus", "weight": 1.7, "releaseProb": 0.52, "sourceCount": 5 }
        ],
        "clusters": [
          { "kind": "topic", "label": "topic", "nodeCount": 2 },
          { "kind": "trait", "label": "trait", "nodeCount": 1 }
        ],
        "stats": { "nodeCount": 3, "edgeCount": 2, "totalNodes": 184, "totalEdges": 512 },
        "overlay": {
          "regions": [
            { "chainyId": "5c8e1f2a-9b4d-4c6e-8a3f-7d2b6e9c1a45", "title": "Product Launch", "colorHex": "#7C5CFF", "bitCount": 42, "completedBitCount": 31 }
          ],
          "synapses": [
            { "chainId": "9a1d4f6b-3c2e-4b7a-8d5c-6e9f2b1a7c34", "title": "Daily writing", "colorHex": "#19B26B", "protocolType": "daily", "totalCompletions": 9, "totalCompletions": 124, "signedPeriodCount": 87, "chainyIds": ["5c8e1f2a-9b4d-4c6e-8a3f-7d2b6e9c1a45"] }
          ]
        },
        "truncated": true,
        "generatedAt": "2026-06-10T09:30:00.000Z"
      }
    }

weight and degree are computed from the returned edges, so they describe the window you received. overlay is present only when requested.

Code Example ​

Use data.twinId from GET /agents/twins/resolve as $TWIN_ID.

bash
curl "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/graph?maxNodes=150&kinds=topic,tool,trait&overlay=productivity" \
  -H "Authorization: Bearer $TOKEN"

GET /agents/twins/{twinId}/brain/memory-graph ​

Description ​

Returns the wiki-style memory map: the most relevant memories as nodes, consolidation links between them, and tag clusters for grouping. Memory content is excerpted to 240 characters — use the memory detail endpoint for the full entry.

Request ​

  • Headers: Authorization: Bearer <token>
  • Path params: twinId (UUID)
  • Query params:
ParameterTypeRequiredDescription
maxNodesintegerNoMemory budget. Default 100, maximum 200 (higher values are clamped)

Response ​

  • 200 OK
    json
    {
      "data": {
        "nodes": [
          {
            "id": "b2e6c1d4-7a3f-4e8b-9c5d-2f1a8e6b4c90",
            "memoryType": "preference",
            "excerpt": "Prefers concise bullet-point summaries over long prose.",
            "importance": 8,
            "relevanceScore": 0.91,
            "tags": ["writing", "style"],
            "isConsolidated": false,
            "flaggedWrongCount": 0,
            "createdAt": "2026-05-28T10:15:00.000Z"
          },
          {
            "id": "d4f8a2b6-1c5e-4a9d-8b3f-6e2c9a5d7b18",
            "memoryType": "preference",
            "excerpt": "Likes short summaries.",
            "importance": 5,
            "relevanceScore": 0.62,
            "tags": ["writing"],
            "isConsolidated": true,
            "flaggedWrongCount": 0,
            "createdAt": "2026-04-12T08:00:00.000Z"
          }
        ],
        "consolidationEdges": [
          { "fromId": "d4f8a2b6-1c5e-4a9d-8b3f-6e2c9a5d7b18", "toId": "b2e6c1d4-7a3f-4e8b-9c5d-2f1a8e6b4c90" }
        ],
        "tagClusters": [
          { "tag": "writing", "memoryIds": ["b2e6c1d4-7a3f-4e8b-9c5d-2f1a8e6b4c90", "d4f8a2b6-1c5e-4a9d-8b3f-6e2c9a5d7b18"] },
          { "tag": "style", "memoryIds": ["b2e6c1d4-7a3f-4e8b-9c5d-2f1a8e6b4c90"] }
        ],
        "stats": { "nodeCount": 2, "consolidationEdgeCount": 1, "tagCount": 2, "totalMemories": 57 },
        "truncated": true,
        "generatedAt": "2026-06-10T09:30:00.000Z"
      }
    }

tagClusters are groupings, not pairwise edges — render them as hulls or clusters around the listed memories.

Code Example ​

bash
curl "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/memory-graph?maxNodes=100" \
  -H "Authorization: Bearer $TOKEN"

GET /agents/twins/{twinId}/brain/memories/ ​

Description ​

Returns one memory in full — the wiki page for that memory: complete content, provenance (where it came from), consolidation relationships, and recent behavioural evidence recorded for the twin.

Request ​

  • Headers: Authorization: Bearer <token>
  • Path params: twinId (UUID), memoryId (UUID)

Response ​

  • 200 OK
    json
    {
      "data": {
        "id": "b2e6c1d4-7a3f-4e8b-9c5d-2f1a8e6b4c90",
        "memoryType": "preference",
        "content": "Prefers concise bullet-point summaries over long prose, especially in status updates.",
        "importance": 8,
        "relevanceScore": 0.91,
        "tags": ["writing", "style"],
        "isConsolidated": false,
        "flaggedWrongCount": 0,
        "createdAt": "2026-05-28T10:15:00.000Z",
        "source": "session",
        "sourceId": "a7c3e9f1-2b6d-4e8a-9c4f-5d1b8e3a6c72",
        "consolidatedInto": null,
        "consolidatedChildren": [
          { "id": "d4f8a2b6-1c5e-4a9d-8b3f-6e2c9a5d7b18", "excerpt": "Likes short summaries." }
        ],
        "evidence": [
          { "type": "chain_completed", "claim": "Keeps a daily writing work pattern", "confidence": 0.84, "recordedAt": "2026-06-09T20:00:00.000Z" }
        ]
      }
    }

To remove or correct a memory, use the forget and flag endpoints in the Twins API.

Code Example ​

Use a memory id from GET /agents/twins/{twinId}/brain/memory-graph's data.nodes[] as $MEMORY_ID.

bash
curl "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/memories/$MEMORY_ID" \
  -H "Authorization: Bearer $TOKEN"

GET /agents/twins/{twinId}/brain/activity ​

Description ​

Returns live activity for the brain over a recent window — this is what makes the brain "shine" while your twin produces. Activation levels are 0..1: a node or chain that was just active is near 1, one at the edge of the window is near 0.

Request ​

  • Headers: Authorization: Bearer <token>
  • Path params: twinId (UUID)
  • Query params:
ParameterTypeRequiredDescription
windowMinutesintegerNoActivity window. Default 60, minimum 5, maximum 1440 (out-of-range values are clamped)

Response ​

  • 200 OK
    json
    {
      "data": {
        "totals": { "runs": 14, "aiSessions": 6, "signedPeriods": 2 },
        "chainActivations": [
          { "chainId": "9a1d4f6b-3c2e-4b7a-8d5c-6e9f2b1a7c34", "level": 1, "lastRunAt": "2026-06-10T09:28:12.000Z", "running": true }
        ],
        "nodeActivations": [
          { "nodeId": "n-typescript", "level": 0.93 },
          { "nodeId": "n-testing", "level": 0.41 }
        ],
        "windowMinutes": 60,
        "cacheTtlSeconds": 30,
        "generatedAt": "2026-06-10T09:30:00.000Z"
      }
    }

cacheTtlSeconds is the snapshot freshness — polling faster than this returns the same data, so use it as your minimum refresh interval. signedPeriods counts your own signed chain periods within the window.

Code Example ​

bash
curl "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/activity?windowMinutes=60" \
  -H "Authorization: Bearer $TOKEN"

GET /agents/twins/{twinId}/brain/chain-impact/ ​

Description ​

Summarises how one of your chains has shaped the brain over the last 30 days: how many pieces of behavioural evidence the chain produced and when it last evolved the twin.

Request ​

  • Headers: Authorization: Bearer <token>
  • Path params: twinId (UUID), chainId (UUID)

Response ​

  • 200 OK
    json
    {
      "data": {
        "chainId": "9a1d4f6b-3c2e-4b7a-8d5c-6e9f2b1a7c34",
        "twinId": "3f7c2a90-5b1e-4d2a-8c4e-1a9d6b3f5e72",
        "strengthenedNodes": [],
        "evidenceCount": 6,
        "lastEvolvedAt": "2026-06-09T20:00:00.000Z"
      }
    }

strengthenedNodes entries have the shape { nodeId, label, kind, weightDelta? }; the array may be empty when the impact cannot be attributed to specific concepts — evidenceCount and lastEvolvedAt always summarise the chain's contribution.

Code Example ​

Use one of your own chain ids from the Chains API as $CHAIN_ID.

bash
curl "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/chain-impact/$CHAIN_ID" \
  -H "Authorization: Bearer $TOKEN"

POST /agents/twins/{twinId}/brain/sample ​

Description ​

Consumes the one-time free brain preview (Free plan). Returns a real brain graph — your actual data, capped at 80 nodes — exactly once per account. A second call returns 403 brain_sample_already_used. Check availability first with sample-status.

Request ​

  • Headers: Authorization: Bearer <token>
  • Path params: twinId (UUID)
  • Body: none

Response ​

  • 200 OK — same shape as GET .../brain/graph (without overlay), capped at 80 nodes:
    json
    {
      "data": {
        "nodes": [
          { "id": "n-typescript", "kind": "topic", "label": "TypeScript", "weight": 4.6, "degree": 2, "lastSeen": "2026-06-10T09:12:41.000Z" }
        ],
        "edges": [
          { "src": "n-typescript", "dst": "n-testing", "weight": 2.9, "releaseProb": 0.74, "sourceCount": 12 }
        ],
        "clusters": [{ "kind": "topic", "label": "topic", "nodeCount": 1 }],
        "stats": { "nodeCount": 1, "edgeCount": 1, "totalNodes": 184, "totalEdges": 512 },
        "truncated": true,
        "generatedAt": "2026-06-10T09:30:00.000Z"
      }
    }
  • 403 Forbidden — preview already used:
    json
    {
      "error": {
        "code": "brain_sample_already_used",
        "message": "The one-time brain preview has already been used on this account. Upgrade to unlock the full Brain Simulator."
      }
    }

Code Example ​

bash
curl -X POST "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/sample" \
  -H "Authorization: Bearer $TOKEN"

GET /agents/twins/{twinId}/brain/sample-status ​

Description ​

Tells you whether the one-time preview is still available on this account, so your UI can show the right call to action before posting to sample.

Request ​

  • Headers: Authorization: Bearer <token>
  • Path params: twinId (UUID)

Response ​

  • 200 OK
    json
    { "data": { "available": true } }

Code Example ​

bash
curl "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/sample-status" \
  -H "Authorization: Bearer $TOKEN"

POST /agents/twins/{twinId}/brain/narrate ​

Description ​

Generates a short AI narration of a region of your brain graph — a focus concept, a path of concepts, or an activation wave. This is the only billed endpoint in the Brain Simulator: usage is charged to your wallet, and each plan has a daily narration budget (Plus 5/day, Pro 25/day, Pro higher capacity 100/day).

The narration is grounded in your graph only — node labels and their connections. Raw memories are never sent to the model.

Request ​

  • Headers: Authorization: Bearer <token>, Content-Type: application/json
  • Path params: twinId (UUID)
  • Body (provide at least one of focusNodeId, pathNodeIds, waveSeedId — if several are set, focusNodeId wins, then pathNodeIds, then waveSeedId):
FieldTypeRequiredDescription
focusNodeIdstring (max 256)No*Narrate around a single node
pathNodeIdsstring[] (max 10 items, each max 256)No*Narrate a path of nodes in order
waveSeedIdstring (max 256)No*Narrate the activation wave seeded at this node
localestringNoen, tr, es, fr, ar, de, pt — default en
  • Example body:
    json
    { "focusNodeId": "n-typescript", "locale": "en" }

Response ​

  • 200 OK
    json
    {
      "data": {
        "narration": "You keep circling back to TypeScript — it is the hub your testing work patterns and deep-focus sessions connect through...",
        "model": "gemini-3.5-flash",
        "creditsCharged": 286
      }
    }
FieldTypeDescription
narrationstringThe generated narration text
modelstringThe model that produced the narration
creditsChargednumberBilled usage committed to your wallet for this narration, measured in model tokens
  • 400 Bad Request — narrate_target_required when no target is provided
  • 402 Payment Required — insufficient_credit when your wallet cannot cover the narration (top up via Wallet)
  • 404 Not Found — narrate_target_not_found when the node ids do not exist in this twin brain
  • 429 Too Many Requests — daily narration budget for your plan is exhausted; resets the next day

Code Example ​

bash
curl -X POST "https://api.chainabit.com/api/v1/agents/twins/$TWIN_ID/brain/narrate" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "pathNodeIds": ["n-typescript", "n-testing"], "locale": "en" }'

GET /public/twins/{username}/brain ​

Description ​

Public, unauthenticated showcase of a brain — available only when the owner has a public profile and has opted in via the publicBrainShowcase twin preference (off by default; see Twins API). The payload is reduced: top topic, tool, and trait nodes only (up to 60 nodes and 180 edges) — never memories, never people. Everything else returns 404.

Changes — including turning the showcase off — can take a few minutes to propagate.

Request ​

  • Path params: username (Chainer username)
  • Rate limit: 30/min

Response ​

  • 200 OK
    json
    {
      "data": {
        "username": "ada",
        "nodes": [
          { "id": "n-typescript", "kind": "topic", "label": "TypeScript", "weight": 4.6 },
          { "id": "n-vitepress", "kind": "tool", "label": "VitePress", "weight": 2.1 },
          { "id": "n-deep-focus", "kind": "trait", "label": "Deep focus", "weight": 1.7 }
        ],
        "edges": [
          { "src": "n-typescript", "dst": "n-vitepress", "weight": 2.1 }
        ],
        "stats": { "nodeCount": 3, "edgeCount": 1 }
      }
    }
  • 404 Not Found — the user does not exist, has a non-public profile, or has not opted in

Code Example ​

bash
curl "https://api.chainabit.com/api/v1/public/twins/ada/brain"

Errors ​

StatusCodeWhenWhat to do
400VALIDATION_ERRORMalformed parameters (non-UUID twinId, unknown kinds value, too many pathNodeIds, …)Fix the request
400narrate_target_requiredNarrate body has none of focusNodeId, pathNodeIds, waveSeedIdProvide a target
401UNAUTHORIZEDMissing or expired tokenRe-authenticate
402insufficient_creditWallet balance cannot cover the narrationTop up your wallet
403FORBIDDENYour plan does not include the feature — the message names the missing feature keyUpgrade your plan
403brain_sample_already_usedThe one-time free preview was already consumed on this accountUpgrade to unlock the full simulator
404NOT_FOUNDTwin, memory, or chain not found or not accessible to you; public brain not availableCheck the id / opt-in state
404narrate_target_not_foundNo matching nodes for the narration target in this twin brainUse node ids from the brain graph
429RATE_LIMIT_EXCEEDEDEndpoint rate limit hit, or the daily narration budget is exhaustedRetry later; narration budgets reset daily

Errors use the standard response envelope. See also the global error codes reference.

Notes ​

  • Replace https://api.chainabit.com/api/v1 with your base URL, e.g. https://api.chainabit.com/api/v1.
  • All twinId, memoryId, and chainId path parameters are UUIDs. Discover your twinId with GET /agents/twins/resolve.
  • Account, workspace, and identity scope are derived from your authentication token — request bodies never include them.
  • Simulating thinking and tracing decision paths happen in the app on top of the graph data — deterministic and free. Only narrate spends from your wallet.

Built with purpose.