Back to Eliza

REST API Examples

packages/docs/examples/rest-api.mdx

1.7.211.6 KB
Original Source

Create REST APIs for your elizaOS agents using your favorite web framework. These examples work without API keys using the classic ELIZA pattern-matching algorithm.

Overview

FrameworkLanguageDirectoryPort
ExpressTypeScriptexamples/rest-api/express/3000
HonoTypeScriptexamples/rest-api/hono/3000
ElysiaTypeScriptexamples/rest-api/elysia/3000
FastAPIPythonexamples/rest-api/fastapi/3000
FlaskPythonexamples/rest-api/flask/3000
Actix WebRustexamples/rest-api/actix/3000
AxumRustexamples/rest-api/axum/3000
RocketRustexamples/rest-api/rocket/3000
<Note> **No API keys required!** These examples use `plugin-eliza-classic` for pattern-matching responses and `plugin-localdb` for local storage. </Note>

Quick Start

<Tabs> <Tab title="Express (TS)"> ```bash cd examples/rest-api/express bun install bun run start ``` </Tab> <Tab title="Hono (TS)"> ```bash cd examples/rest-api/hono bun install bun run start ``` </Tab> <Tab title="FastAPI (Py)"> ```bash cd examples/rest-api/fastapi python -m venv venv && source venv/bin/activate pip install -r requirements.txt python server.py ``` </Tab> <Tab title="Actix (Rust)"> ```bash cd examples/rest-api/actix cargo run --release ``` </Tab> </Tabs>

Common API

All examples expose the same REST API:

GET /

Returns information about the agent.

bash
curl http://localhost:3000/

Response:

json
{
  "name": "Eliza",
  "bio": "A Rogerian psychotherapist simulation",
  "status": "ready"
}

GET /health

Health check endpoint.

bash
curl http://localhost:3000/health

Response:

json
{
  "status": "healthy",
  "runtime": "elizaos",
  "uptime": 12345
}

POST /chat

Send a message to the agent.

bash
curl -X POST http://localhost:3000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello, how are you?"}'

Response:

json
{
  "response": "How do you do. Please state your problem.",
  "character": "Eliza",
  "userId": "550e8400-e29b-41d4-a716-446655440000"
}

Complete Examples

<Tabs> <Tab title="Express (TypeScript)"> ```typescript import express from 'express'; import { AgentRuntime, ModelType } from '@elizaos/core'; import { elizaClassicPlugin } from '@elizaos/plugin-eliza-classic'; import { plugin as localdbPlugin } from '@elizaos/plugin-localdb'; import { v4 as uuidv4 } from 'uuid';

const app = express(); app.use(express.json());

// Character definition const character = { name: 'Eliza', bio: 'A Rogerian psychotherapist simulation created at MIT in 1966.', };

// Initialize runtime const runtime = new AgentRuntime({ character, plugins: [localdbPlugin, elizaClassicPlugin], });

await runtime.initialize();

// Routes app.get('/', (req, res) => { res.json({ name: character.name, bio: character.bio, status: 'ready', }); });

app.get('/health', (req, res) => { res.json({ status: 'healthy', runtime: 'elizaos-typescript', uptime: process.uptime(), }); });

app.post('/chat', async (req, res) => { const { message, userId = uuidv4() } = req.body;

if (!message) { return res.status(400).json({ error: 'Message is required' }); }

try { const response = await runtime.useModel(ModelType.TEXT_LARGE, { prompt: message, });

res.json({
  response: String(response),
  character: character.name,
  userId,
});

} catch (error) { res.status(500).json({ error: 'Failed to process message' }); } });

const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(Eliza API running on http://localhost:${PORT}); });

  </Tab>
  <Tab title="FastAPI (Python)">
```python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from elizaos import AgentRuntime, Character
from elizaos.plugin_eliza_classic import eliza_classic_plugin
import uuid
import time

app = FastAPI()

# Character definition
character = Character(
    name="Eliza",
    bio="A Rogerian psychotherapist simulation created at MIT in 1966.",
)

# Initialize runtime
runtime = AgentRuntime(
    character=character,
    plugins=[eliza_classic_plugin],
)

start_time = time.time()

class ChatRequest(BaseModel):
    message: str
    userId: str | None = None

class ChatResponse(BaseModel):
    response: str
    character: str
    userId: str

@app.on_event("startup")
async def startup():
    await runtime.initialize()

@app.get("/")
async def root():
    return {
        "name": character.name,
        "bio": character.bio,
        "status": "ready",
    }

@app.get("/health")
async def health():
    return {
        "status": "healthy",
        "runtime": "elizaos-python",
        "uptime": time.time() - start_time,
    }

@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    if not request.message:
        raise HTTPException(status_code=400, detail="Message is required")

    user_id = request.userId or str(uuid.uuid4())

    try:
        from elizaos import ChannelType, Content, Memory, string_to_uuid

        message = Memory(
            entity_id=string_to_uuid(user_id),
            room_id=string_to_uuid("rest-api-room"),
            content=Content(
                text=request.message,
                source="rest-api",
                channel_type=ChannelType.DM.value,
            ),
        )
        result = await runtime.message_service.handle_message(runtime, message)
        response = (
            result.response_content.text
            if result.response_content and result.response_content.text
            else ""
        )

        return ChatResponse(
            response=str(response),
            character=character.name,
            userId=user_id,
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail="Failed to process message")

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=3000)
</Tab> <Tab title="Actix Web (Rust)"> ```rust use actix_web::{web, App, HttpServer, HttpResponse, Result}; use elizaos::{AgentRuntime, RuntimeOptions, parse_character}; use elizaos_plugin_eliza_classic::create_eliza_classic_plugin; use serde::{Deserialize, Serialize}; use std::sync::Arc; use std::time::Instant; use uuid::Uuid;

#[derive(Deserialize)] struct ChatRequest { message: String, #[serde(rename = "userId")] user_id: Option<String>, }

#[derive(Serialize)] struct ChatResponse { response: String, character: String, #[serde(rename = "userId")] user_id: String, }

#[derive(Serialize)] struct InfoResponse { name: String, bio: String, status: String, }

#[derive(Serialize)] struct HealthResponse { status: String, runtime: String, uptime: f64, }

struct AppState { runtime: Arc<AgentRuntime>, character_name: String, character_bio: String, start_time: Instant, }

async fn root(data: web::Data<AppState>) -> Result<HttpResponse> { Ok(HttpResponse::Ok().json(InfoResponse { name: data.character_name.clone(), bio: data.character_bio.clone(), status: "ready".to_string(), })) }

async fn health(data: web::Data<AppState>) -> Result<HttpResponse> { Ok(HttpResponse::Ok().json(HealthResponse { status: "healthy".to_string(), runtime: "elizaos-rust".to_string(), uptime: data.start_time.elapsed().as_secs_f64(), })) }

async fn chat( data: web::Data<AppState>, req: web::Json<ChatRequest>, ) -> Result<HttpResponse> { let user_id = req.user_id.clone() .unwrap_or_else(|| Uuid::new_v4().to_string());

let content = elizaos::types::Content {
    text: Some(req.message.clone()),
    source: Some("rest-api".to_string()),
    channel_type: Some(elizaos::types::ChannelType::Dm),
    ..Default::default()
};

let mut msg =
    elizaos::types::Memory::new(elizaos::types::UUID::new_v4(), elizaos::types::UUID::new_v4(), content);

let result = data.runtime
    .message_service()
    .handle_message(data.runtime.as_ref(), &mut msg, None, None)
    .await
    .map_err(|_| actix_web::error::ErrorInternalServerError("Failed to process"))?;

let response = result
    .response_content
    .and_then(|c| c.text)
    .unwrap_or_default();

Ok(HttpResponse::Ok().json(ChatResponse {
    response,
    character: data.character_name.clone(),
    user_id,
}))

}

#[actix_web::main] async fn main() -> std::io::Result<()> { let character = parse_character(r#"{ "name": "Eliza", "bio": "A Rogerian psychotherapist simulation created at MIT in 1966." }"#).unwrap();

let runtime = AgentRuntime::new(RuntimeOptions {
    character: Some(character.clone()),
    plugins: vec![create_eliza_classic_plugin()],
    ..Default::default()
}).await.unwrap();

runtime.initialize().await.unwrap();

let state = web::Data::new(AppState {
    runtime: Arc::new(runtime),
    character_name: character.name.clone(),
    character_bio: character.bio.clone(),
    start_time: Instant::now(),
});

println!("Eliza API running on http://localhost:3000");

HttpServer::new(move || {
    App::new()
        .app_data(state.clone())
        .route("/", web::get().to(root))
        .route("/health", web::get().to(health))
        .route("/chat", web::post().to(chat))
})
.bind("0.0.0.0:3000")?
.run()
.await

}

  </Tab>
</Tabs>

---

## Framework Comparison

| Feature | Express | Hono | Elysia | FastAPI | Flask | Actix | Axum | Rocket |
|---------|---------|------|--------|---------|-------|-------|------|--------|
| Async | ✅ | ✅ | ✅ | ✅ | ⚠️ | ✅ | ✅ | ✅ |
| Type Safety | ⚠️ | ✅ | ✅ | ✅ | ⚠️ | ✅ | ✅ | ✅ |
| Performance | Good | Great | Great | Good | Fair | Excellent | Excellent | Great |
| Bundle Size | Medium | Small | Small | N/A | N/A | Small | Small | Medium |

---

## Testing the API

```bash
# Get agent info
curl http://localhost:3000/

# Health check
curl http://localhost:3000/health

# Send a message
curl -X POST http://localhost:3000/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "I am feeling sad today"}'

# Expected response:
# {"response": "I am sorry to hear that you are feeling that way.", ...}

Configuration

All examples support the PORT environment variable:

bash
PORT=8080 bun run start        # TypeScript
PORT=8080 python server.py     # Python
PORT=8080 cargo run --release  # Rust

Adding OpenAI Support

To use OpenAI instead of pattern matching, swap the plugin:

<Tabs> <Tab title="TypeScript"> ```typescript import { openaiPlugin } from '@elizaos/plugin-openai'; import { plugin as sqlPlugin } from '@elizaos/plugin-sql';

const runtime = new AgentRuntime({ character, plugins: [sqlPlugin, openaiPlugin], // Replace elizaClassicPlugin });

  </Tab>
  <Tab title="Python">
```python
from elizaos_plugin_openai import get_openai_plugin

runtime = AgentRuntime(
    character=character,
    plugins=[get_openai_plugin()],
)
</Tab> <Tab title="Rust"> ```rust use elizaos_plugin_openai::create_openai_plugin;

let runtime = AgentRuntime::new(RuntimeOptions { character: Some(character), plugins: vec![create_openai_plugin()?], ..Default::default() }).await?;

  </Tab>
</Tabs>

<Warning>
  OpenAI requires `OPENAI_API_KEY` environment variable.
</Warning>

---

## Next Steps

<CardGroup cols={2}>
  <Card title="Browser Examples" icon="browser" href="/examples/browser">
    Run agents client-side without a server
  </Card>
  <Card title="Serverless Examples" icon="cloud" href="/examples/serverless">
    Deploy to AWS, GCP, Vercel, or Cloudflare
  </Card>
</CardGroup>