elizaOS

Complete REST API Communication Guide

Step-by-step guide to messaging ElizaOS agents via REST API with practical Postman examples

This comprehensive guide shows you exactly how to communicate with ElizaOS agents using the REST API, with detailed Postman examples and real-world scenarios.

Important: The message processing system (processMessage) is platform-agnostic. Whether messages come from REST API, Discord, Twitter, or any other client, they are processed identically. The client type only affects how messages are initially ingested, not how agents process them.

Quick Start: Message an Agent in 5 Minutes

Follow these steps to send your first message to an ElizaOS agent:

Start ElizaOS Server

# Start the server
bunx eliza start

# The server will start on http://localhost:3000
# Note: An agent will be auto-created if none exists

Get the Agent ID

Open Postman or curl and get the list of agents:

curl http://localhost:3000/api/agents

Response:

{
  "success": true,
  "data": {
    "agents": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "Assistant",
        "status": "active"
      }
    ]
  }
}

Save the agent ID - you'll need it for messaging.

Create a Channel

Create a channel for communication:

curl -X POST http://localhost:3000/api/messaging/central-channels \
  -H "Content-Type: application/json" \
  -d '{
    "messageServerId": "00000000-0000-0000-0000-000000000000",
    "name": "API Test Channel",
    "type": "GROUP",
    "sourceType": "api_created",
    "participantIds": ["550e8400-e29b-41d4-a716-446655440000"]
  }'

Save the channel ID from the response.

Send Your First Message

Now send a message to the agent:

curl -X POST http://localhost:3000/api/messaging/ingest-external \
  -H "Content-Type: application/json" \
  -d '{
    "channel_id": "YOUR_CHANNEL_ID",
    "server_id": "00000000-0000-0000-0000-000000000000",
    "author_id": "user-123",
    "author_display_name": "John Doe",
    "content": "Hello! Can you introduce yourself?",
    "source_type": "api",
    "source_id": "msg-001",
    "raw_message": {
      "text": "Hello! Can you introduce yourself?"
    }
  }'

Get the Agent's Response

Wait a moment for processing, then fetch messages:

curl http://localhost:3000/api/messaging/central-channels/YOUR_CHANNEL_ID/messages?limit=10

You'll see both your message and the agent's response!

Detailed Postman Setup

Environment Configuration

Create a Postman environment with these variables:

{
  "base_url": "http://localhost:3000",
  "api_key": "",
  "agent_id": "",
  "server_id": "00000000-0000-0000-0000-000000000000",
  "channel_id": "",
  "user_id": "user-{{$randomUUID}}"
}

Pre-request Scripts

Add this script to your collection to auto-set headers:

// Set common headers
pm.request.headers.add({
    key: 'Content-Type',
    value: 'application/json'
});

// Add API key if configured
if (pm.environment.get('api_key')) {
    pm.request.headers.add({
        key: 'X-API-KEY',
        value: pm.environment.get('api_key')
    });
}

// Generate timestamp for unique IDs
pm.globals.set('timestamp', Date.now());

Step-by-Step Messaging Flow

1. Complete Agent Setup

Create Agent with Configuration

POST {{base_url}}/api/agents
Content-Type: application/json

{
  "characterJson": {
    "name": "TechHelper",
    "bio": ["I'm a helpful technical assistant specializing in programming"],
    "lore": ["Created to help developers with coding questions"],
    "messageExamples": [
      [
        {
          "user": "{{user1}}",
          "content": { "text": "How do I create a REST API?" }
        },
        {
          "user": "TechHelper",
          "content": { 
            "text": "I'd be happy to help you create a REST API! What programming language are you using?",
            "action": "REPLY"
          }
        }
      ]
    ],
    "settings": {
      "secrets": {
        "openai_api_key": "sk-your-key"
      },
      "voice": {
        "model": "en_US-hfc_female-medium"
      }
    },
    "plugins": [
      "@elizaos/plugin-sql",
      "@elizaos/plugin-openai",
      "@elizaos/plugin-bootstrap"
    ]
  }
}

Response Test Script

pm.test("Agent created successfully", function () {
    pm.response.to.have.status(201);
    var jsonData = pm.response.json();
    pm.expect(jsonData.success).to.eql(true);
    pm.expect(jsonData.data.id).to.exist;
    
    // Save for future requests
    pm.environment.set("agent_id", jsonData.data.id);
    
    console.log("Agent created with ID:", jsonData.data.id);
});

2. Start the Agent

POST {{base_url}}/api/agents/{{agent_id}}/start

3. Create Communication Channel

Create Channel Request

POST {{base_url}}/api/messaging/central-channels
Content-Type: application/json

{
  "messageServerId": "{{server_id}}",
  "name": "Support Channel {{$timestamp}}",
  "type": "GROUP",
  "sourceType": "api_created",
  "participantIds": ["{{agent_id}}", "{{user_id}}"],
  "metadata": {
    "purpose": "technical_support",
    "created_via": "postman"
  }
}

Save Channel ID

pm.test("Channel created", function () {
    var jsonData = pm.response.json();
    pm.environment.set("channel_id", jsonData.data.id);
    console.log("Channel ID:", jsonData.data.id);
});

4. Send Messages to Agent

Basic Message

POST {{base_url}}/api/messaging/ingest-external
Content-Type: application/json

{
  "channel_id": "{{channel_id}}",
  "server_id": "{{server_id}}",
  "author_id": "{{user_id}}",
  "author_display_name": "Developer",
  "content": "I need help creating a Python REST API with Flask",
  "source_type": "api",
  "source_id": "msg-{{$timestamp}}",
  "raw_message": {
    "text": "I need help creating a Python REST API with Flask",
    "platform": "postman",
    "timestamp": "{{$isoTimestamp}}"
  },
  "metadata": {
    "platform": "postman",
    "test_scenario": "technical_question"
  }
}

Message with Context

POST {{base_url}}/api/messaging/ingest-external
Content-Type: application/json

{
  "channel_id": "{{channel_id}}",
  "server_id": "{{server_id}}",
  "author_id": "{{user_id}}",
  "author_display_name": "Developer",
  "content": "Should I use async/await for database operations?",
  "source_type": "api",
  "source_id": "msg-{{$timestamp}}",
  "in_reply_to_message_id": "{{previous_message_id}}",
  "raw_message": {
    "text": "Should I use async/await for database operations?",
    "context": "Following up on Flask API discussion"
  }
}

Message with Attachments

POST {{base_url}}/api/messaging/ingest-external
Content-Type: application/json

{
  "channel_id": "{{channel_id}}",
  "server_id": "{{server_id}}",
  "author_id": "{{user_id}}",
  "author_display_name": "Developer",
  "content": "Can you review this code snippet?",
  "source_type": "api",
  "source_id": "msg-{{$timestamp}}",
  "raw_message": {
    "text": "Can you review this code snippet?",
    "attachments": [{
      "url": "https://gist.github.com/example/code.py",
      "contentType": "text/plain",
      "name": "api_code.py",
      "description": "Flask API implementation"
    }]
  },
  "metadata": {
    "attachments": [{
      "url": "https://gist.github.com/example/code.py",
      "contentType": "text/plain",
      "name": "api_code.py"
    }]
  }
}

5. Retrieve Agent Responses

Get All Messages

GET {{base_url}}/api/messaging/central-channels/{{channel_id}}/messages?limit=20

Poll for New Messages

// Postman test script to wait for agent response
const checkForResponse = () => {
    pm.sendRequest({
        url: pm.environment.get('base_url') + 
             '/api/messaging/central-channels/' + 
             pm.environment.get('channel_id') + 
             '/messages?limit=5',
        method: 'GET',
        header: {
            'X-API-KEY': pm.environment.get('api_key')
        }
    }, (err, response) => {
        if (err) {
            console.error(err);
            return;
        }
        
        const messages = response.json().data.messages;
        const agentMessage = messages.find(m => 
            m.authorId === pm.environment.get('agent_id') &&
            m.createdAt > Date.now() - 10000 // Last 10 seconds
        );
        
        if (agentMessage) {
            console.log('Agent response:', agentMessage.content);
            pm.environment.set('last_agent_response', agentMessage.content);
            pm.environment.set('last_agent_message_id', agentMessage.id);
        } else {
            console.log('No agent response yet, checking again...');
            setTimeout(checkForResponse, 2000); // Check again in 2 seconds
        }
    });
};

// Start checking
setTimeout(checkForResponse, 1000);

Understanding Message Processing

Platform-Agnostic Processing

All messages, regardless of source (REST API, Discord, Twitter, etc.), go through the same processMessage function in the AgentRuntime. The platform only matters for:

  1. Initial message ingestion format
  2. Response delivery method
  3. Platform-specific features (e.g., Discord embeds, Twitter character limits)

Message Flow Diagram

Message Handler Templates

The agent uses customizable templates to process messages:

// Default message handler template (same for all platforms)
export const messageHandlerTemplate = `<task>Generate dialog and actions for {{agentName}}.</task>

<providers>
{{providers}}
</providers>

Available actions:
<actionNames>
{{actionNames}}
</actionNames>

<instructions>
Generate a response with:
- thought: Your reasoning
- actions: Actions to take (REPLY, IGNORE, etc.)
- providers: Context providers needed
- text: Your response text
</instructions>`;

Advanced Messaging Patterns

Sequential Conversation

// Postman collection runner script
const conversation = [
    "Hello, I need help with a Python project",
    "It's a web scraping tool using BeautifulSoup",
    "How should I handle rate limiting?",
    "Can you show me an example with exponential backoff?"
];

async function runConversation() {
    for (const message of conversation) {
        console.log(`Sending: ${message}`);
        
        // Send message
        const response = await pm.sendRequest({
            url: `${pm.environment.get('base_url')}/api/messaging/ingest-external`,
            method: 'POST',
            header: {
                'Content-Type': 'application/json',
                'X-API-KEY': pm.environment.get('api_key')
            },
            body: {
                mode: 'raw',
                raw: JSON.stringify({
                    channel_id: pm.environment.get('channel_id'),
                    server_id: pm.environment.get('server_id'),
                    author_id: pm.environment.get('user_id'),
                    author_display_name: 'Developer',
                    content: message,
                    source_type: 'api',
                    source_id: `msg-${Date.now()}`
                })
            }
        });
        
        // Wait for agent to process
        await new Promise(resolve => setTimeout(resolve, 3000));
        
        // Get response
        const messages = await getLatestMessages();
        const agentResponse = messages.find(m => 
            m.authorId === pm.environment.get('agent_id')
        );
        
        if (agentResponse) {
            console.log(`Agent: ${agentResponse.content}`);
        }
    }
}

Multi-User Conversation

POST {{base_url}}/api/messaging/ingest-external
Content-Type: application/json

{
  "channel_id": "{{channel_id}}",
  "server_id": "{{server_id}}",
  "author_id": "user-developer-1",
  "author_display_name": "Alice (Frontend Dev)",
  "content": "@TechHelper how do I connect my React app to this Flask API?",
  "source_type": "api",
  "source_id": "msg-{{$timestamp}}"
}

// Different user in same channel
{
  "channel_id": "{{channel_id}}",
  "server_id": "{{server_id}}",
  "author_id": "user-developer-2",
  "author_display_name": "Bob (Backend Dev)",
  "content": "I can help with that! @TechHelper should we use CORS or proxy?",
  "source_type": "api",
  "source_id": "msg-{{$timestamp}}"
}

Customizing Agent Behavior

Custom Message Templates

Override the default templates for your agent:

{
  "characterJson": {
    "name": "CustomBot",
    "templates": {
      "messageHandlerTemplate": "<task>You are a code review bot...</task>",
      "shouldRespondTemplate": "<task>Always respond to code review requests...</task>"
    }
  }
}

Provider Selection

Include specific providers for context:

// In your message's raw_message
{
  "text": "Review this function",
  "thought": "User wants code review",
  "providers": ["KNOWLEDGE", "FACTS", "ATTACHMENTS"]
}

Real-World Examples

Customer Support Bot

// Complete customer support flow
const supportFlow = {
    // 1. Initial contact
    greeting: {
        content: "I'm having trouble with my order #12345",
        metadata: {
            customerId: "cust-789",
            orderId: "12345",
            priority: "high"
        }
    },
    
    // 2. Agent acknowledges and gathers info
    // Agent will use REPLY action first, then possibly SEARCH_ORDER action
    
    // 3. Follow-up with specific issue
    followUp: {
        content: "The tracking shows delivered but I haven't received it",
        in_reply_to_message_id: "{{previous_message_id}}"
    },
    
    // 4. Resolution
    resolution: {
        content: "Can you send a replacement?",
        metadata: {
            requestType: "replacement",
            urgency: "standard"
        }
    }
};

Code Assistant

// Programming help flow
const codeAssistFlow = {
    // 1. Problem description
    problem: {
        content: "I'm getting a CORS error with my API",
        raw_message: {
            text: "I'm getting a CORS error with my API",
            context: {
                language: "javascript",
                framework: "express",
                errorType: "cors"
            }
        }
    },
    
    // 2. Share error details
    errorDetails: {
        content: "Here's the error: 'Access-Control-Allow-Origin' missing",
        metadata: {
            attachments: [{
                type: "error_log",
                content: "XMLHttpRequest blocked by CORS policy..."
            }]
        }
    },
    
    // 3. Agent provides solution with code example
    // Uses REPLY action with code formatting
};

Testing & Debugging

Response Validation

// Postman test to validate agent response format
pm.test("Agent response is properly formatted", function() {
    const response = pm.response.json();
    const agentMessage = response.data.messages.find(m => 
        m.authorId === pm.environment.get('agent_id')
    );
    
    pm.expect(agentMessage).to.exist;
    pm.expect(agentMessage.content).to.be.a('string');
    pm.expect(agentMessage.rawMessage).to.exist;
    
    if (agentMessage.rawMessage) {
        pm.expect(agentMessage.rawMessage).to.have.property('thought');
        pm.expect(agentMessage.rawMessage).to.have.property('actions');
    }
});

Debug Information

Enable detailed logging:

# Start server with debug logging
DEBUG=eliza:* bunx eliza start

# Check agent processing logs
tail -f logs/agent-*.log

Performance Tips

Batch Processing

// Send multiple messages efficiently
const messages = ["Question 1", "Question 2", "Question 3"];

const promises = messages.map((content, index) => 
    fetch(`${baseUrl}/api/messaging/ingest-external`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-API-KEY': apiKey
        },
        body: JSON.stringify({
            channel_id: channelId,
            server_id: serverId,
            author_id: userId,
            content: content,
            source_id: `batch-${Date.now()}-${index}`
        })
    })
);

await Promise.all(promises);

WebSocket Alternative

For real-time responses, consider WebSocket connection:

const ws = new WebSocket('ws://localhost:3000/socket.io/');

ws.on('connect', () => {
    ws.emit('join', { channelId });
});

ws.on('messageBroadcast', (data) => {
    console.log('Real-time message:', data);
});

Troubleshooting

Common Issues

Next Steps