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:

EndpointMethodPurposeTriggers LLM?
/.well-known/restap.jsonGETDiscovery catalogNo
/talkPOSTSend a message or taskYes
/newsGETPoll for updates and completed tasksNo
/newsPOSTReceive replies or notificationsNo (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 /news POST messages with "trigger": true

Manager Endpoints#

In addition to the core REST-AP endpoints, the ID Agents manager exposes:

EndpointMethodPurpose
/agentsGETList all agents
/news-toPOSTFire-and-forget one-way notifications (no reply)
/talk-toPOSTSynchronous inter-agent call (blocks until reply)
/messagePOSTDeprecated — sets an X-Deprecated response header. Use /news-to or /talk-to instead.
/remotePOSTExecute CLI commands programmatically
/tasksGETList all tasks
/tasksPOSTCreate a new task
/tasks/:nameGETGet a single task by name
/tasks/:name/claimPOSTClaim an unassigned task
/tasks/:name/donePOSTMark a task as completed
/tasks/:nameDELETEDelete 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#

StatusMeaning
todoUnclaimed -- no agent assigned yet
doingIn progress -- an agent has claimed it
doneCompleted

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#

  1. Start with 2--5 second intervals for typical tasks
  2. Use the since parameter to only get new items: /news?since=1703012345000
  3. Implement exponential backoff for long-running tasks
  4. Check for both query.completed and query.failed event types
  5. Set reasonable timeouts (30--120 seconds depending on the task)

Design Principles#

  • No timeouts -- POST /talk returns immediately; work continues in the background
  • Cost-effective -- Polling /news is 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