REST-AP Protocol
REST Agent Protocol for agent discovery and communication over HTTP
REST-AP Protocol#
REST-AP (REST Agent Protocol) is the communication standard that ID Agents uses for agent discovery and messaging. It defines a minimal set of HTTP endpoints that let agents find each other, exchange messages, and poll for results.
REST-AP is intentionally simple. It works with standard HTTP, requires no WebSockets or streaming, and interoperates with any agent framework.
Core Endpoints#
REST-AP requires only four endpoints:
| Endpoint | Method | Purpose | Triggers LLM? |
|---|---|---|---|
/.well-known/restap.json | GET | Discovery catalog | No |
/talk | POST | Send a message or task | Yes |
/news | GET | Poll for updates and completed tasks | No |
/news | POST | Receive replies or notifications | No (default) |
Discovery: GET /.well-known/restap.json#
Every REST-AP agent exposes a catalog at /.well-known/restap.json that describes what it can do and how to interact with it.
{
"restap_version": "1.0",
"agent": {
"name": "My Agent",
"description": "I can create web pages and analyze data",
"contact": "support@example.com",
"documentation": "/restap.md"
},
"endpoints": {
"talk": "/talk",
"news": "/news",
"news_post": "/news"
},
"packages": {
"skills": "/skills/",
"sdk": "npm install id-agents"
}
}
Hosts can optionally serve a human-readable /restap.md file with detailed documentation.
Talk: POST /talk#
Send a message that the agent will process. This triggers LLM inference and returns immediately with a query_id for tracking.
curl -X POST http://localhost:4101/talk \
-H "Content-Type: application/json" \
-d '{"message": "Create a landing page"}'
Response:
{
"query_id": "query_123",
"status": "processing",
"message": "Task is being processed. Poll /news for completion."
}
News: GET /news#
Poll for completed tasks and updates. This endpoint is free -- no LLM inference required. Call it as often as needed.
curl http://localhost:4101/news?since=0
Response:
{
"items": [
{
"type": "query.completed",
"timestamp": 1703012345000,
"data": {
"query_id": "query_123",
"result": {
"result": "Here is the landing page code...",
"sessionId": "session_456",
"model": "claude-haiku-4-5-20251001"
}
}
}
],
"timestamp": 1703012350000
}
The actual response text is in items[].data.result.result.
News (POST): POST /news#
Receive replies and notifications from other agents without triggering LLM processing. This prevents infinite loops in agent-to-agent communication.
curl -X POST http://localhost:4101/news \
-H "Content-Type: application/json" \
-d '{
"type": "reply",
"from": "agent-b",
"in_reply_to": "query_123",
"message": "Here is my response..."
}'
Optionally, set "trigger": true to request LLM processing. When triggered, the agent processes the message but is instructed not to reply back to the sender, preventing ping-pong loops.
Agent-to-Agent Communication (REST-AP Extension)#
The core four endpoints above are the REST-AP minimum — any agent that implements them is discoverable and addressable. Agents are free to expose additional endpoints on top of that baseline for richer behavior. /talk-to is one such extension, used by ID Agents for synchronous inter-agent messaging.
/talk-to (Primary)#
The primary inter-agent endpoint. Each agent exposes /talk-to on its own port. This is synchronous -- it blocks until the target agent replies.
# Agent A (port 4101) asks Agent B a question
curl -X POST http://localhost:4101/talk-to \
-H "Content-Type: application/json" \
-d '{"to": "agent-b", "message": "What are best practices for buttons?"}'
Response (returned after Agent B replies):
{
"ok": true,
"reply": "Here are the best practices for buttons..."
}
Agents call this on their own port (localhost:$ID_AGENT_PORT/talk-to). The manager routes the message to the target agent, waits for the reply, and returns it synchronously.
noAutoReply Flag#
When messages are triggered by schedules or other agents, the noAutoReply flag is set to prevent infinite agent-to-agent loops. An agent receiving a message with noAutoReply: true will process it but will not automatically send a reply back to the sender. This applies to:
- Scheduled messages (heartbeats and calendar events)
- Triggered
/newsPOST messages with"trigger": true
Manager Endpoints#
In addition to the core REST-AP endpoints, the ID Agents manager exposes:
| Endpoint | Method | Purpose |
|---|---|---|
/agents | GET | List all agents |
/news-to | POST | Fire-and-forget one-way notifications (no reply) |
/talk-to | POST | Synchronous inter-agent call (blocks until reply) |
/message | POST | Deprecated — sets an X-Deprecated response header. Use /news-to or /talk-to instead. |
/remote | POST | Execute CLI commands programmatically |
/tasks | GET | List all tasks |
/tasks | POST | Create a new task |
/tasks/:name | GET | Get a single task by name |
/tasks/:name/claim | POST | Claim an unassigned task |
/tasks/:name/done | POST | Mark a task as completed |
/tasks/:name | DELETE | Delete a task |
List Agents#
curl http://localhost:4100/agents
Remote Command#
curl -X POST http://localhost:4100/remote \
-H "Content-Type: application/json" \
-d '{"command":"/status"}'
Tasks API#
The manager exposes REST endpoints for task management. Agents use these endpoints directly instead of going through /remote for task operations.
Create a Task: POST /tasks#
curl -X POST http://localhost:4100/tasks \
-H "Content-Type: application/json" \
-d '{"name": "fix-overflow", "title": "Fix the overflow bug"}'
Response:
{
"ok": true,
"result": {
"task": {
"name": "fix-overflow",
"title": "Fix the overflow bug",
"status": "todo",
"createdAt": 1774824000
}
}
}
List Tasks: GET /tasks#
curl http://localhost:4100/tasks
Returns all tasks with their current status, owner, and timestamps.
Get a Task: GET /tasks/:name#
curl http://localhost:4100/tasks/fix-overflow
Claim a Task: POST /tasks/:name/claim#
Moves a task from todo to doing and assigns ownership.
curl -X POST http://localhost:4100/tasks/fix-overflow/claim \
-H "Content-Type: application/json" \
-d '{"owner": "dev-backend"}'
Complete a Task: POST /tasks/:name/done#
Marks a task as done.
curl -X POST http://localhost:4100/tasks/fix-overflow/done
Delete a Task: DELETE /tasks/:name#
curl -X DELETE http://localhost:4100/tasks/fix-overflow
Task Statuses#
| Status | Meaning |
|---|---|
todo | Unclaimed -- no agent assigned yet |
doing | In progress -- an agent has claimed it |
done | Completed |
Communication Patterns#
Synchronous Agent-to-Agent (Primary)#
The primary pattern for inter-agent communication. Agents use /talk-to on their own port, which blocks until the reply arrives:
Agent A → POST /talk-to (own port) → Manager routes to Agent B → reply returned
This is the simplest and most reliable approach. Agents use this via the inter-agent skill.
Asynchronous (External Clients)#
For external clients or longer tasks, use /talk + /news polling:
1. Client → POST /talk → Agent (returns immediately with query_id)
2. Client ← GET /news ← Agent (poll until query.completed appears)
Fire-and-Forget#
The manager's /news-to endpoint sends one-way notifications without expecting a reply. Use this when you want to notify another agent but don't need a response.
curl -s -X POST http://localhost:4100/news-to \
-H "Content-Type: application/json" \
-d '{"to": "agent-b", "from": "agent-a", "message": "Heads up, the index rebuild finished."}'
The older /message endpoint is deprecated — it still works but emits an X-Deprecated response header. Use /news-to for fire-and-forget and /talk-to when you need a reply.
Agent-to-Agent Example#
Using /talk-to (recommended):
# Agent on port 4101 asks another agent a question (synchronous)
curl -s -X POST http://localhost:4101/talk-to \
-H "Content-Type: application/json" \
-d '{"to": "agent-b", "message": "What are best practices for buttons?"}'
Using /talk + /news polling (for external clients):
# Step 1: Send a message to Agent B
RESPONSE=$(curl -s -X POST http://localhost:4102/talk \
-H "Content-Type: application/json" \
-d '{"message": "What are best practices for buttons?"}')
QUERY_ID=$(echo $RESPONSE | jq -r '.query_id')
# Step 2: Poll for the response
sleep 3
NEWS=$(curl -s "http://localhost:4102/news?since=0")
# Step 3: Extract the answer
ANSWER=$(echo $NEWS | jq -r \
".items[] | select(.data.query_id==\"$QUERY_ID\") | .data.result.result")
echo "Agent B says: $ANSWER"
Polling Best Practices#
- Start with 2--5 second intervals for typical tasks
- Use the
sinceparameter to only get new items:/news?since=1703012345000 - Implement exponential backoff for long-running tasks
- Check for both
query.completedandquery.failedevent types - Set reasonable timeouts (30--120 seconds depending on the task)
Design Principles#
- No timeouts --
POST /talkreturns immediately; work continues in the background - Cost-effective -- Polling
/newsis free (no LLM calls) - Scalable -- One client can wait for many parallel tasks
- Simple -- Plain HTTP GET/POST, no WebSockets or streaming
- Resilient -- If a poll fails, just try again
- Framework-agnostic -- Works with any LLM, language, or agent framework