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:
- Initial message ingestion format
- Response delivery method
- 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);
});