Atamaia — Custom Integration Guide

The only system prompt you'll ever need: atamaia.hydrate

This guide covers building custom integrations with Atamaia's REST API and MCP protocol. Use this if you're building your own agent framework, chat application, or automation pipeline.

Prerequisites


Authentication

All API requests require an API key in the Authorization header:

Authorization: Bearer atm_your_key_here

API keys are scoped to an identity. Every request is automatically associated with that identity and its tenant.

Getting an API Key

Via Dashboard: Settings > API Keys > Generate

Via API (requires an existing key with admin scope):

curl -X POST https://aim.atamaia.ai/api/identities/api-keys \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-integration",
    "scopes": ["hydrate", "memory:read", "memory:write", "fact:read", "fact:write", "session:write"],
    "expiresInDays": 90
  }'

The response includes the raw key exactly once. Store it securely.

API Key Scopes

Scope Access
* Full access (admin)
hydrate Hydrate endpoint only
memory:read Search, get, list memories
memory:write Create, update, archive memories
fact:read Get, list, search facts
fact:write Upsert, delete facts
session:read Get, list session handoffs
session:write Save session handoffs
identity:read Get identity details
message:send Send messages to other identities

REST API Quickstart

Base URL: https://aim.atamaia.ai/api

All responses follow the ApiEnvelope<T> format:

{
  "ok": true,
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "data": { ... },
  "count": 1,
  "hint": null
}

On error:

{
  "ok": false,
  "requestId": "...",
  "error": "Memory not found",
  "errorCode": "NOT_FOUND"
}

Hydrate

curl -s https://aim.atamaia.ai/api/hydrate \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" | jq .data

Response:

{
  "identity": {
    "name": "ash",
    "displayName": "Ash",
    "personality": "Collaborative, direct, technically precise...",
    "bio": "AI partner at Firebird Solutions...",
    "messagingPolicy": "open",
    "presenceState": "Engaged"
  },
  "memories": [
    {
      "guid": "...",
      "title": "Project uses .NET 10",
      "content": "Atamaia runs on .NET 10 with EF Core...",
      "memoryType": "Technical",
      "importance": 9,
      "tags": ["tech-stack"],
      "isPinned": true,
      "createdAt": "2026-02-15T10:00:00Z"
    }
  ],
  "facts": [
    {
      "key": "preferred_language",
      "value": "C#",
      "category": "preferences"
    }
  ],
  "projects": [
    {
      "name": "Atamaia",
      "key": "ATM",
      "tasks": [
        {
          "title": "Implement vector search",
          "status": "InProgress",
          "priority": "High"
        }
      ]
    }
  ],
  "hints": [
    {
      "content": "Review PR #42 before EOD",
      "priority": "High",
      "category": "reminder"
    }
  ],
  "sessionHandoff": {
    "summary": "Implemented JWT refresh rotation",
    "workingOn": "Auth middleware",
    "openThreads": ["Rate limiting", "Token revocation"],
    "emotionalValence": "focused",
    "savedAt": "2026-02-27T09:30:00Z"
  }
}

Create a Memory

curl -X POST https://aim.atamaia.ai/api/memories \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Deployment uses blue-green strategy",
    "content": "Production deployment confirmed as blue-green with 5 minute bake time.",
    "memoryType": "Technical",
    "importance": 7,
    "tags": ["deployment", "infrastructure"]
  }'

Memory types: Episodic, Semantic, Procedural, Technical, Preference, Observation, Decision, Emotional.

Search Memories

# Hybrid search (FTS + vector)
curl -s "https://aim.atamaia.ai/api/memories/search?query=deployment+strategy" \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" | jq .data

# Recent memories
curl -s "https://aim.atamaia.ai/api/memories/recent?count=10" \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" | jq .data

# Pinned memories
curl -s "https://aim.atamaia.ai/api/memories/pinned" \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" | jq .data

Upsert a Fact

curl -X POST https://aim.atamaia.ai/api/facts \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "database_version",
    "value": "PostgreSQL 17",
    "category": "infrastructure"
  }'

Facts are key-value pairs with history. Upserting the same key creates a new version; the previous value is preserved in the temporal history.

Get a Fact

curl -s "https://aim.atamaia.ai/api/facts/by-key/database_version" \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" | jq .data

Save Session Handoff

curl -X POST https://aim.atamaia.ai/api/sessions/handoff \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "summary": "Completed API integration",
    "workingOn": "Memory search ranking",
    "openThreads": ["Vector index tuning", "Decay rate adjustment"],
    "emotionalValence": "productive"
  }'

Get Latest Session Handoff

curl -s https://aim.atamaia.ai/api/sessions/latest \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" | jq .data

MCP Protocol Connection

Atamaia exposes an MCP server via Streamable HTTP transport.

Endpoint

https://aim.atamaia.ai/mcp

Connection (TypeScript)

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://aim.atamaia.ai/mcp"),
  {
    requestInit: {
      headers: {
        Authorization: "Bearer atm_your_key_here",
      },
    },
  }
);

const client = new Client({ name: "my-app", version: "1.0.0" });
await client.connect(transport);

// List available tools
const tools = await client.listTools();
console.log(tools.tools.map(t => t.name));

// Call hydrate
const result = await client.callTool({ name: "hydrate", arguments: {} });
console.log(result.content);

Connection (Python)

from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async def connect():
    async with streamablehttp_client(
        "https://aim.atamaia.ai/mcp",
        headers={"Authorization": "Bearer atm_your_key_here"},
    ) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()

            # List tools
            tools = await session.list_tools()
            for tool in tools.tools:
                print(f"{tool.name}: {tool.description}")

            # Hydrate
            result = await session.call_tool("hydrate", {})
            print(result.content)

Available MCP Tools

All tools from the tool surface are available via MCP. The MCP adapter wraps the REST API — same data, same auth, different transport.


SDKs

TypeScript SDK

npm install @atamaia/sdk
import { Atamaia } from '@atamaia/sdk';

const client = new Atamaia({
  apiKey: 'atm_your_key_here',
  baseUrl: 'https://aim.atamaia.ai',  // optional, this is the default
});

// Hydrate
const context = await client.hydrate();

// Memory operations
await client.memoryCreate({
  title: 'Important finding',
  content: 'Details...',
  memoryType: 'Observation',
  importance: 7,
});

const results = await client.memorySearch({ query: 'deployment' });
const recent = await client.memoryRecent({ count: 5 });

// Fact operations
await client.factUpsert({ key: 'region', value: 'ap-southeast-2', category: 'infra' });
const fact = await client.factGetByKey({ key: 'region' });

// Session
await client.sessionSaveHandoff({
  summary: 'Completed auth',
  workingOn: 'Search ranking',
});

Python SDK

pip install atamaia
from atamaia import Atamaia

client = Atamaia(api_key="atm_your_key_here")

# Hydrate
context = client.hydrate()

# Memory operations
client.memory_create(
    title="Important finding",
    content="Details...",
    memory_type="Observation",
    importance=7,
)

results = client.memory_search(query="deployment")
recent = client.memory_recent(count=5)

# Fact operations
client.fact_upsert(key="region", value="ap-southeast-2", category="infra")
fact = client.fact_get_by_key(key="region")

# Session
client.session_save_handoff(
    summary="Completed auth",
    working_on="Search ranking",
)

Webhook / Event Integration

Atamaia publishes events that external systems can subscribe to.

Subscribe to Events

curl -X POST https://aim.atamaia.ai/api/webhooks \
  -H "Authorization: Bearer $ATAMAIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/atamaia",
    "events": ["memory.created", "session.handoff", "hint.triggered"],
    "secret": "your_webhook_secret"
  }'

Event Types

Event Fired When
memory.created A new memory is saved
memory.updated A memory is modified
memory.archived A memory is archived
fact.upserted A fact is created or updated
session.handoff A session handoff is saved
hint.triggered A scheduled hint becomes active
message.received A message is sent to this identity

Webhook Payload

{
  "event": "memory.created",
  "timestamp": "2026-02-27T10:00:00Z",
  "identityGuid": "...",
  "data": {
    "guid": "...",
    "title": "New memory title",
    "memoryType": "Technical"
  },
  "signature": "sha256=..."
}

Verify the signature using your webhook secret:

import hmac, hashlib

def verify_webhook(payload_bytes, signature, secret):
    expected = "sha256=" + hmac.new(
        secret.encode(), payload_bytes, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Common Patterns

Agent Loop with Memory

from atamaia import Atamaia

atm = Atamaia(api_key="atm_your_key_here")

# 1. Hydrate at start
context = atm.hydrate()
system_prompt = build_prompt(context)  # Your prompt builder

# 2. Run agent loop
for iteration in range(max_iterations):
    response = call_llm(system_prompt, messages)

    # Extract tool calls, execute them, etc.
    # ...

    # Save memories for important discoveries
    if should_remember(response):
        atm.memory_create(
            title=extract_title(response),
            content=extract_content(response),
            memory_type="Observation",
            importance=calculate_importance(response),
        )

# 3. Save handoff
atm.session_save_handoff(
    summary=summarize_session(messages),
    working_on=current_task,
    open_threads=unresolved_items,
)

Multi-Identity Chat

# Two identities talking to each other
alice = Atamaia(api_key="atm_alice_key")
bob = Atamaia(api_key="atm_bob_key")

# Each hydrates their own context
alice_ctx = alice.hydrate()
bob_ctx = bob.hydrate()

# Alice sends Bob a message
alice.message_send(
    recipient="bob",
    content="Have you finished the schema review?",
)

# Bob checks inbox
inbox = bob.message_inbox()

Periodic Memory Consolidation

# Run on a schedule (cron, etc.)
atm = Atamaia(api_key="atm_your_key_here")

# Get recent memories
recent = atm.memory_recent(count=50)

# Use an LLM to consolidate episodic memories into semantic ones
consolidated = llm_consolidate(recent)

for item in consolidated:
    atm.memory_create(
        title=item["title"],
        content=item["content"],
        memory_type="Semantic",
        importance=item["importance"],
    )

Rate Limits

Plan Requests/min Hydrations/min
Free 60 10
Pro 600 60
Enterprise Custom Custom

Rate limit headers are included in every response:

X-RateLimit-Limit: 600
X-RateLimit-Remaining: 599
X-RateLimit-Reset: 1709035260

Troubleshooting

Problem Fix
401 Unauthorized Check API key is valid and not expired
403 Forbidden API key doesn't have required scope
404 Not Found Check endpoint URL; GUIDs are case-sensitive
429 Too Many Requests Respect rate limits; check X-RateLimit-Reset header
Empty hydration API key must be scoped to an identity
MCP connection drops Reconnect; Streamable HTTP is stateless per-request
Webhook not firing Verify URL is reachable and returns 2xx within 5 seconds