# Nunchi AI MaaS

> MaaS (Memory-as-a-Service) is an enterprise memory API powered by the
> Synapsis engine. It provides persistent, contextual memory for AI agents
> and applications via a simple REST API.

- Authentication: Bearer token via `Authorization` header (key prefix: `mk_maas_`)
- Base URL: `https://maas.nunchiai.com/v1`
- Workspace scoping: `X-Workspace-Id` header required on all runtime requests
- Onboarding endpoint: `POST /api/v1/billing/maas/checkout-session`
- Runtime endpoints use `/v1/` prefix

## Core Documentation

- [Quick Start](https://maas.nunchiai.com/docs/quickstart.md): 5-minute integration with complete curl examples
- [API Reference](https://maas.nunchiai.com/docs/api-reference.md): All endpoints with full request/response schemas
- [Memory Atoms](https://maas.nunchiai.com/docs/concepts/atoms.md): Atom types, confidence scores, decay, storage
- [Anchors](https://maas.nunchiai.com/docs/concepts/anchors.md): Organizing memory by context scope
- [Recall & Injection](https://maas.nunchiai.com/docs/concepts/recall.md): Retrieving relevant memory before responses
- [Feedback Loop](https://maas.nunchiai.com/docs/concepts/feedback.md): Reinforcing memory that influenced output

## Integration Guides

- [Character Chat](https://maas.nunchiai.com/docs/guides/character-chat.md): Anchor-per-pair pattern for character memory
- [Enterprise Tutor](https://maas.nunchiai.com/docs/guides/enterprise-tutor.md): Learning progress tracking with memory atoms
- [Editorial / Content](https://maas.nunchiai.com/docs/guides/editorial.md): MaaS-powered content generation (IndiePulse pattern)

## Reference

- [Error Codes](https://maas.nunchiai.com/docs/errors.md): All error responses with resolution steps
- [SDK](https://maas.nunchiai.com/docs/sdk.md): Official SDK status and wrapper guidance
- [Changelog](https://maas.nunchiai.com/docs/changelog.md): Version history and breaking changes

---

# Quick Start

Use this path when a human buyer has finished checkout and wants a coding agent to start the integration.

## What you need

- `API key` from the MaaS success page
- `Base URL`: `https://maas.nunchiai.com/v1`
- `X-Workspace-Id` for the target environment
- A `service_source` chosen during checkout

## Step 1. Create the checkout session

```bash
curl -X POST https://maas.nunchiai.com/api/v1/billing/maas/checkout-session \
  -H 'Content-Type: application/json' \
  -d '{
    "company_name": "Acme Studio",
    "admin_email": "ops@acme.test",
    "pricing_model": "enterprise_usage",
    "service_source": "enterprise-tutor"
  }'
```

```json
{
  "checkout_session_id": "cs_test_123",
  "url": "https://checkout.stripe.com/c/pay/cs_test_123",
  "success_url": "https://maas.nunchiai.com/billing/maas/success?checkout_session_id={CHECKOUT_SESSION_ID}",
  "cancel_url": "https://maas.nunchiai.com/billing/maas/cancel",
  "service_source": "enterprise-tutor",
  "pricing_model": "enterprise_usage",
  "contract_version": "2026-03-01"
}
```

### Errors

- `400 Bad Request` — `company_name`, `admin_email`, `pricing_model`, or `service_source` is invalid.
- `402 Payment Required` — billing is paused for the hosted service.
- `500 Internal Server Error` — Stripe price configuration is missing.

## Step 2. Complete checkout and open the success page

The buyer completes Stripe checkout and returns to:

```text
https://maas.nunchiai.com/billing/maas/success?checkout_session_id=cs_test_123
```

The success page provisions the tenant automatically and shows:

- organization slug
- service source label
- workspace id
- first API key
- AHOP handoff block

## Step 3. Make the first runtime call

Use the issued key and workspace id immediately.

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/recall \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_id": "smoke-test",
    "query": "hello"
  }'
```

```json
{
  "items": [],
  "session_id": "c67d4f42-0b6d-4f94-beb8-22eb24a8a6df",
  "service_source": "enterprise-tutor",
  "workspace_id": "acme-prod"
}
```

### Errors

- `400 Bad Request` — API key is invalid or `X-Workspace-Id` is missing.
- `402 Payment Required` — billing account is blocked.
- `403 Forbidden` — access policy denies this workspace/key combination.
- `429 Too Many Requests` — retry with backoff.

## What to do next

- Read [API Reference](/docs/api-reference.md) for the full surface.
- Read [Character Chat](/docs/guides/character-chat.md) if the buyer chose `enterprise-tutor`.
- Read [Editorial / Content](/docs/guides/editorial.md) if the buyer chose `maas-enterprise`.

---

# API Reference

This page lists the hosted MaaS endpoints that matter for onboarding and runtime use.

## Onboarding endpoint

### `POST /api/v1/billing/maas/checkout-session`

Create the hosted checkout session.

```bash
curl -X POST https://maas.nunchiai.com/api/v1/billing/maas/checkout-session \
  -H 'Content-Type: application/json' \
  -d '{
    "company_name": "Acme Studio",
    "admin_email": "ops@acme.test",
    "pricing_model": "enterprise_usage",
    "service_source": "maas-enterprise"
  }'
```

```json
{
  "checkout_session_id": "cs_test_123",
  "url": "https://checkout.stripe.com/c/pay/cs_test_123",
  "success_url": "https://maas.nunchiai.com/billing/maas/success?checkout_session_id={CHECKOUT_SESSION_ID}",
  "cancel_url": "https://maas.nunchiai.com/billing/maas/cancel",
  "service_source": "maas-enterprise"
}
```

### Errors

- `400` invalid request body
- `402` billing paused
- `500` Stripe price configuration missing

## Runtime endpoints

All runtime calls use:

- `Authorization: Bearer <API_KEY>` or `x-api-key: <API_KEY>`
- `X-Workspace-Id: <WORKSPACE_ID>`

### `POST /v1/anchors`

Create a reusable memory scope.

```bash
curl -X POST https://maas.nunchiai.com/v1/anchors \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Character Pair",
    "type": "chat-log",
    "metadata": {
      "lane": "user-42:aria",
      "service_source": "enterprise-tutor"
    }
  }'
```

```json
{
  "anchor_id": "be2d5afd-8ec2-44d1-bfb3-e1eb4cb2c9b1",
  "name": "Character Pair",
  "type": "chat-log",
  "metadata": {
    "lane": "user-42:aria",
    "service_source": "enterprise-tutor"
  }
}
```

### `POST /v1/atoms`

Store durable memory inside an anchor.

```bash
curl -X POST https://maas.nunchiai.com/v1/atoms \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_id": "be2d5afd-8ec2-44d1-bfb3-e1eb4cb2c9b1",
    "content": "User likes rainy jazz playlists.",
    "source_type": "prd",
    "metadata": {
      "atom_type": "preference",
      "user_external_id": "user-42"
    },
    "chunking": { "enabled": false }
  }'
```

```json
{
  "atom_ids": ["dc3b98c4-c6af-478f-88c2-6582d95d5a11"],
  "stored_count": 1,
  "service_source": "enterprise-tutor"
}
```

### `POST /v1/recall`

Recall memory for a single anchor.

```bash
curl -X POST https://maas.nunchiai.com/v1/recall \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_id": "be2d5afd-8ec2-44d1-bfb3-e1eb4cb2c9b1",
    "query": "What music does the user like?",
    "limit": 5
  }'
```

```json
{
  "items": [
    {
      "atom_id": "dc3b98c4-c6af-478f-88c2-6582d95d5a11",
      "content": "User likes rainy jazz playlists.",
      "score": 0.9121
    }
  ],
  "session_id": "e6d339b8-a71d-4413-88ab-cbd982cf9765"
}
```

### `POST /v1/feedback`

Reinforce memory that actually influenced the output.

```bash
curl -X POST https://maas.nunchiai.com/v1/feedback \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "session_id": "e6d339b8-a71d-4413-88ab-cbd982cf9765",
    "success": true,
    "used_memory_atom_ids": ["dc3b98c4-c6af-478f-88c2-6582d95d5a11"]
  }'
```

```json
{
  "ok": true
}
```

## Memory convenience endpoints

### `POST /v1/memory/ingest`

Bulk ingest memory with `user_external_id` and `session_id`.

### `POST /v1/memory/recall`

Recall memory for end-user products, including `enterprise-tutor`.

### `POST /v1/memory/hydrate`

Return bounded prompt context from stored memory.

## Common runtime errors

- `400` invalid key or missing workspace header
- `402` billing blocked
- `403` access policy denied
- `404` anchor not found
- `429` rate limited

---

# Memory Atoms

Atoms are the durable memory units stored in MaaS.

## What an atom contains

- `anchor_id` — the memory scope
- `content` — the natural-language memory payload
- `source_type` — storage lane such as `prd` or `chat-log`
- `metadata` — product-specific fields such as `atom_type`, `user_external_id`, `session_id`
- `confidence` — optional relevance or certainty signal if your product uses it

## Write an atom

```bash
curl -X POST https://maas.nunchiai.com/v1/atoms \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_id": "be2d5afd-8ec2-44d1-bfb3-e1eb4cb2c9b1",
    "content": "Learner still confuses TCP and UDP.",
    "source_type": "prd",
    "metadata": {
      "atom_type": "misconception",
      "user_external_id": "learner-17",
      "confidence": 0.82
    },
    "chunking": { "enabled": false }
  }'
```

```json
{
  "atom_ids": ["88f1b2ff-61d1-4675-ae74-634c78e8aa61"],
  "stored_count": 1,
  "service_source": "enterprise-tutor"
}
```

## Storage rules

- Store meaningful observations, not greetings or filler.
- Keep `content` human-readable. Do not store compressed codewords.
- Put product taxonomy in `metadata.atom_type`.
- Use `source_type=prd` for durable facts and preferences.
- Use `source_type=chat-log` for recent conversational observations.

## Character chat examples

- `preference`
- `emotional_state`
- `relationship_event`
- `backstory_reveal`
- `promise`
- `boundary`

## Errors

- `400` malformed request body or invalid key
- `403` access policy denied
- `404` anchor missing
- `429` write rate limited

---

# Anchors

Anchors define the scope that memory belongs to.

## When to create an anchor

Create an anchor when your product needs one stable memory lane.

Examples:

- one anchor per `user + character` pair
- one anchor per learner
- one anchor per editorial lane
- one anchor per product workflow

## Create an anchor

```bash
curl -X POST https://maas.nunchiai.com/v1/anchors \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Editorial Lane",
    "type": "chat-log",
    "metadata": {
      "lane": "MAAS_ANCHOR_EDITORIAL",
      "project": "indiepulse-editorial"
    }
  }'
```

```json
{
  "anchor_id": "6629df4e-6ee8-4d1d-ae8a-bb1f2a35a2ab",
  "name": "Editorial Lane",
  "type": "chat-log",
  "metadata": {
    "lane": "MAAS_ANCHOR_EDITORIAL",
    "project": "indiepulse-editorial"
  }
}
```

## Naming rules

- Keep the anchor strategy stable after production launch.
- Encode scope in metadata even if the anchor name is human-readable.
- Reuse anchors. Do not create a new anchor every turn.

## Recommended defaults

- Character chat: one anchor per `user + character`
- Tutor: one anchor per learner
- Editorial: one anchor per lane such as `EDITORIAL`, `TRENDS`, `MAKERS`

## Errors

- `400` invalid body or missing workspace header
- `402` billing blocked
- `403` access policy denied
- `429` rate limited

---

# Recall & Injection

Recall is the retrieval step that happens before generation.

## Anchor-scoped recall

Use `POST /v1/recall` when your product already knows the anchor.

```bash
curl -X POST https://maas.nunchiai.com/v1/recall \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_id": "6629df4e-6ee8-4d1d-ae8a-bb1f2a35a2ab",
    "query": "What topics are trending this week?",
    "limit": 6
  }'
```

```json
{
  "items": [
    {
      "atom_id": "a2c3e4d5-8a54-43df-9f13-b6694cb29e6b",
      "content": "Indie founders are discussing rising infra bills.",
      "score": 0.873
    }
  ],
  "session_id": "0897cb2f-ecf6-45ff-a84c-3dbf560bb0c2"
}
```

## User-scoped recall

Use `POST /v1/memory/recall` when your product is centered on `user_external_id`.

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/recall \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "user_external_id": "user-42",
    "session_id": "session-2026-04-01-001",
    "query": "What topics should I follow up on?"
  }'
```

```json
{
  "items": [
    {
      "atom_id": "3fdb5de0-8862-4f61-b7e1-2aaf0f4c1f09",
      "content": "User asked to continue the movie discussion next time.",
      "score": 0.891
    }
  ]
}
```

## Hydrate bounded context

Use `POST /v1/memory/hydrate` when you need a compact context block for a prompt.

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/hydrate \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_ids": ["6629df4e-6ee8-4d1d-ae8a-bb1f2a35a2ab"],
    "query": "Summarize the latest editorial memory.",
    "token_budget": 500
  }'
```

```json
{
  "context_text": "- Indie founders are discussing rising infra bills.\n- Readers responded well to billing transparency angles.",
  "used_atom_ids": [
    "a2c3e4d5-8a54-43df-9f13-b6694cb29e6b",
    "bb3a95e9-593f-46b9-8ca1-93841e8243e0"
  ]
}
```

## Injection rules

- Recall before every model response.
- Keep injected memory bounded.
- Send feedback only when the recalled memory changed the answer.

## Errors

- `400` invalid query, key, or workspace header
- `403` access policy denied
- `404` anchor missing
- `429` read rate limited

---

# Feedback Loop

Feedback tells MaaS which recalled memory actually mattered.

## When to send feedback

Send positive feedback only if:

- recall returned one or more atoms
- the final response actually used recalled memory
- you can name the `used_memory_atom_ids`

Do not send feedback for filler generations or fallback responses that ignored memory.

## Send feedback

```bash
curl -X POST https://maas.nunchiai.com/v1/feedback \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "session_id": "0897cb2f-ecf6-45ff-a84c-3dbf560bb0c2",
    "success": true,
    "used_memory_atom_ids": [
      "3fdb5de0-8862-4f61-b7e1-2aaf0f4c1f09"
    ]
  }'
```

```json
{
  "ok": true
}
```

## Minimal evaluator contract

Your app should decide:

- whether memory was used
- which atoms were used
- whether the final answer was high-confidence enough to reinforce

## Errors

- `400` invalid session id, invalid key, or invalid atom id list
- `403` access policy denied
- `404` recall session not found
- `429` rate limited

---

# Character Chat

This guide uses `service_source: enterprise-tutor`.

On human-facing pages, this appears as `Character Chat / Enterprise Tutor`.

## Default integration pattern

- create one anchor per `user + character` pair
- recall before every reply
- store meaningful memory after every reply
- keep transcript state outside MaaS if you want, but persist durable memory in MaaS
- send feedback only when recalled memory influenced the final answer

## Create the pair anchor

```bash
curl -X POST https://maas.nunchiai.com/v1/anchors \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "User 42 and Aria",
    "type": "chat-log",
    "metadata": {
      "lane": "user-42:aria",
      "user_external_id": "user-42",
      "character_id": "aria"
    }
  }'
```

## Store durable memory

```bash
curl -X POST https://maas.nunchiai.com/v1/atoms \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_id": "be2d5afd-8ec2-44d1-bfb3-e1eb4cb2c9b1",
    "content": "User asked to continue the movie discussion next time.",
    "source_type": "prd",
    "metadata": {
      "atom_type": "promise",
      "user_external_id": "user-42",
      "session_id": "session-005"
    },
    "chunking": { "enabled": false }
  }'
```

```json
{
  "atom_ids": ["f44c85cc-f63d-4fbc-9f5d-5b84df02d77d"],
  "stored_count": 1
}
```

## Recall before generation

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/recall \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: acme-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "user_external_id": "user-42",
    "session_id": "session-006",
    "query": "What should the character remember before replying?"
  }'
```

```json
{
  "items": [
    {
      "atom_id": "f44c85cc-f63d-4fbc-9f5d-5b84df02d77d",
      "content": "User asked to continue the movie discussion next time.",
      "score": 0.893
    }
  ]
}
```

## Recommended atom taxonomy

- `preference`
- `emotional_state`
- `relationship_event`
- `backstory_reveal`
- `promise`
- `boundary`

## Do not store

- greetings
- acknowledgements
- filler turns
- low-confidence fallback text

## Errors

- `400` invalid key or missing workspace header
- `402` billing blocked
- `403` access policy denied
- `404` missing anchor
- `429` rate limited

---

# Enterprise Tutor

This guide uses `service_source: enterprise-tutor` for learner-specific memory.

## Default integration pattern

- create one anchor per learner
- track mastery, misconceptions, and struggle points as atoms
- recall memory before each teaching turn
- store what teaching style worked or failed
- use confidence values to reflect uncertainty

## Create the learner anchor

```bash
curl -X POST https://maas.nunchiai.com/v1/anchors \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: tutor-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Learner 17",
    "type": "chat-log",
    "metadata": {
      "lane": "learner-17",
      "user_external_id": "learner-17"
    }
  }'
```

## Write learning observations

```bash
curl -X POST https://maas.nunchiai.com/v1/atoms \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: tutor-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_id": "77568c95-bcb6-4c36-b9b7-d4eaaad43cd3",
    "content": "Learner understands subnet masks but still misses CIDR notation.",
    "source_type": "prd",
    "metadata": {
      "atom_type": "misconception",
      "user_external_id": "learner-17",
      "confidence": 0.78
    },
    "chunking": { "enabled": false }
  }'
```

## Recall before teaching

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/recall \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: tutor-prod" \
  -H 'Content-Type: application/json' \
  -d '{
    "user_external_id": "learner-17",
    "session_id": "lesson-2026-04-03",
    "query": "What should the tutor adapt for this learner?"
  }'
```

```json
{
  "items": [
    {
      "atom_id": "9113f776-bbf3-4fd4-84f0-d7e9c19e1de2",
      "content": "Learner understands subnet masks but still misses CIDR notation.",
      "score": 0.905
    }
  ]
}
```

## Suggested atom types

- `concept_mastered`
- `misconception`
- `learning_style`
- `struggle_point`
- `goal`
- `follow_up`

## Errors

- `400` invalid key or missing workspace header
- `402` billing blocked
- `403` access policy denied
- `404` missing anchor
- `429` rate limited

---

# Editorial / Content

This guide uses `service_source: maas-enterprise`.

## Default integration pattern

- create one anchor per domain lane
- ingest content or observations into the correct lane
- recall before drafting
- hydrate prompt context when the current input is sparse
- reinforce only the recalled memory that changed the output

## Recommended lanes

- `MAAS_ANCHOR_EDITORIAL`
- `MAAS_ANCHOR_TRENDS`
- `MAAS_ANCHOR_MAKERS`

## Create the editorial anchor

```bash
curl -X POST https://maas.nunchiai.com/v1/anchors \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: indiepulse-editorial" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Editorial Lane",
    "type": "chat-log",
    "metadata": {
      "lane": "MAAS_ANCHOR_EDITORIAL",
      "project": "indiepulse"
    }
  }'
```

## Ingest editorial memory

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/ingest \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: indiepulse-editorial" \
  -H 'Content-Type: application/json' \
  -d '{
    "user_external_id": "indiepulse-editorial",
    "session_id": "editorial-brief-2026-04-03",
    "messages": [
      { "role": "system", "content": "Editorial memory ingest." },
      { "role": "user", "content": "Founders are reacting strongly to infra pricing shifts." }
    ]
  }'
```

## Recall before drafting

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/recall \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: indiepulse-editorial" \
  -H 'Content-Type: application/json' \
  -d '{
    "user_external_id": "indiepulse-editorial",
    "session_id": "draft-2026-04-03",
    "query": "What angles should the editorial draft emphasize?"
  }'
```

## Hydrate a bounded context block

```bash
curl -X POST https://maas.nunchiai.com/v1/memory/hydrate \
  -H "Authorization: Bearer mk_maas_example" \
  -H "X-Workspace-Id: indiepulse-editorial" \
  -H 'Content-Type: application/json' \
  -d '{
    "anchor_ids": ["EDITORIAL_ANCHOR_ID", "TRENDS_ANCHOR_ID"],
    "query": "Prepare a 500-token briefing on founder pricing sentiment.",
    "token_budget": 500
  }'
```

## Errors

- `400` invalid key or missing workspace header
- `402` billing blocked
- `403` access policy denied
- `404` missing anchor
- `429` rate limited

---

# Error Codes

Use the JSON response body first. MaaS runtime errors are intentionally short.

## `400 Bad Request`

Common causes:

- API key is missing or invalid
- `X-Workspace-Id` is missing
- request body is malformed

```json
{
  "error": "bad_request",
  "message": "X-Workspace-Id is required"
}
```

Resolution:

- send a valid `Authorization` or `x-api-key`
- send `X-Workspace-Id`
- validate JSON before retry

## `402 Payment Required`

Common cause:

- billing account is blocked or delinquent

```json
{
  "error": "billing_access_blocked",
  "message": "runtime access is blocked for this billing account"
}
```

Resolution:

- fix billing status
- retry after the account is active

## `403 Forbidden`

Common cause:

- access policy denies this key/workspace combination

```json
{
  "error": "forbidden",
  "message": "runtime access denied by access policy"
}
```

Resolution:

- verify the key belongs to the intended tenant
- verify the workspace id matches the allowed runtime scope

## `404 Not Found`

Common cause:

- requested anchor or recall session does not exist

```json
{
  "error": "not_found",
  "message": "anchor not found"
}
```

Resolution:

- create the anchor first with `POST /v1/anchors`
- do not assume an anchor exists after checkout

## `429 Too Many Requests`

Common cause:

- request rate exceeded for the current key/workspace

```json
{
  "error": "rate_limited",
  "message": "too many requests"
}
```

Resolution:

- retry with exponential backoff
- reduce fan-out and duplicate recall calls

---

# SDK

MaaS does not require an official SDK for integration.

## Recommended approach

Use raw HTTPS requests first. Build a thin client wrapper only after your request shapes are stable.

## Suggested wrapper surface

- `createAnchor(payload)`
- `storeAtom(payload)`
- `recall(payload)`
- `feedback(payload)`
- `ingestMemory(payload)`
- `hydrateMemory(payload)`

## Minimal JavaScript wrapper

```js
async function maasRequest(path, body, { apiKey, workspaceId }) {
  const response = await fetch(`https://maas.nunchiai.com/v1${path}`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${apiKey}`,
      "X-Workspace-Id": workspaceId,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(body)
  });

  const json = await response.json();
  if (!response.ok) throw new Error(`${response.status}: ${json.message || json.error}`);
  return json;
}
```

## Errors

- `400` validate headers and payload
- `402` billing blocked
- `403` access policy denied
- `404` anchor missing
- `429` apply retry/backoff

---

# Changelog

This changelog tracks public docs and onboarding surface changes.

## 2026-03-31

- introduced AHOP handoff messaging on the success page
- added `llms.txt` and `llms-full.txt`
- added canonical Markdown documentation routes
- rebuilt the public site around agent-first onboarding

## 2026-03-29

- unified hosted onboarding around checkout -> success auto-provisioning
- localized billing success and cancel pages

## 2026-03-27

- added hosted billing docs for MaaS
- separated human onboarding from operator key issuance
