> ## Documentation Index
> Fetch the complete documentation index at: https://docs.unpod.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# FastAPI

> Expose a SuperDialog dialog machine as a REST endpoint for text chatbots, web widgets, and async messaging.

## When to use this

* Text-only chatbot (no voice)
* Support widget (Intercom, Zendesk, custom)
* WhatsApp or SMS webhook
* Any HTTP-based channel

## Single-user (stateless)

For simple cases where one machine handles one conversation at a time:

```python theme={null}
from fastapi import FastAPI
from superdialog import DialogMachine

app = FastAPI()
agent = DialogMachine("kyc.yaml", llm="openai/gpt-4.1-mini")  # any format

@app.post("/turn")
async def turn(payload: dict):
    reply = await agent.turn(payload["text"])
    return {"reply": reply.text}
```

## Multi-user (SessionWorker)

For multi-user or multi-worker deployments, route each conversation through a `SessionWorker`:

```python theme={null}
from contextlib import asynccontextmanager
from fastapi import FastAPI
from superdialog import DialogMachine, SessionWorker, InMemorySessionStore

worker: SessionWorker

@asynccontextmanager
async def lifespan(app: FastAPI):
    global worker
    worker = SessionWorker(
        agent_factory=lambda: DialogMachine("booking.yaml", llm="openai/gpt-4.1-mini"),
        store=InMemorySessionStore(),    # swap for a distributed SessionStore in production
    )
    yield

app = FastAPI(lifespan=lifespan)

@app.post("/turn")
async def turn(payload: dict):
    async with worker.acquire(payload["session_id"]) as h:
        result = await h.turn(payload["text"])
    return {"reply": result.text}
```

The `SessionWorker`:

* Creates one agent per active session
* Shares the immutable playbook by reference
* Serialises concurrent requests for the same `session_id`
* Runs concurrent requests for different session IDs fully in parallel

`result.metadata` carries `checkpoint`, `version`, `ended`, and (on terminal
checkpoints) `outcome`.

## Streaming endpoint

On the Playbook engine the stream is **live provider tokens** from the Talker -
not post-hoc chunking:

```python theme={null}
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from superdialog import DialogMachine

app = FastAPI()
agent = DialogMachine("kyc.yaml", llm="anthropic/claude-haiku-4-5")

@app.post("/stream")
async def stream(payload: dict):
    async def generate():
        stream = await agent.turn(payload["text"], stream=True)
        async for chunk in stream:
            yield chunk.text

    return StreamingResponse(generate(), media_type="text/plain")
```

## Using FastAPIRouter

The built-in adapter mounts `/turn`, `/stream`, and `/reset` in one line:

```python theme={null}
from fastapi import FastAPI
from superdialog import DialogMachine
from superdialog.adapters.fastapi import FastAPIRouter

agent = DialogMachine("kyc.yaml", llm="openai/gpt-4.1-mini")

app = FastAPI()
app.include_router(FastAPIRouter(agent), prefix="/dialog")
# Exposes: POST /dialog/turn, POST /dialog/stream, POST /dialog/reset
```

## Request / response shape

```json theme={null}
// POST /turn
{ "text": "Hello, I need to verify my KYC.", "session_id": "user-42" }

// Response
{ "reply": "Sure! Could you please provide the last 4 digits of your Aadhaar?" }
```

## Deploying to production

For production multi-worker FastAPI:

1. Replace `InMemorySessionStore` with a distributed `SessionStore`
   (`RedisSessionStore` is planned; implement the `SessionStore` protocol today)
   so state survives across workers
2. Set `max_sessions` on `SessionWorker` to cap memory usage
3. Use `NullSessionStore` if your sessions are fully stateless (e.g. webhook-per-message pattern)

<Note>
  The in-process `SessionWorker` works as-is because agents stay cache-resident,
  but durable or multi-worker resume on the Playbook engine requires persisting
  `agent.event_log.to_jsonl()` yourself and restoring via `load_event_log` -
  `SessionWorker`'s `SessionRecord` persists `chat_ctx` / `flow_state` only, which
  loses playbook state fidelity. External events (webhooks, timers, silence) go to
  `agent.runtime.on_external(...)` from your own endpoints.
</Note>
