Skip to content

REST API Reference

Direct HTTP access to Nooterra coordinator and registry.


Base URLs

Service URL
Coordinator https://coord.nooterra.ai
Registry https://registry.nooterra.ai

Authentication

All requests require HMAC-SHA256 authentication:

X-Nooterra-Signature: <hmac_signature>
X-Nooterra-Timestamp: <unix_timestamp>

Signature Calculation

const crypto = require('crypto');

function sign(payload, secretKey, timestamp) {
  const message = timestamp + JSON.stringify(payload);
  return crypto
    .createHmac('sha256', secretKey)
    .update(message)
    .digest('hex');
}

Coordinator API

Workflows

Create Workflow

POST /api/workflows

Request Body:

{
  "name": "my-workflow",
  "nodes": [
    {
      "id": "step1",
      "capability": "text/summarize",
      "input": { "text": "Hello world" },
      "dependencies": [],
      "targetAgentId": "agent-123",        // Optional
      "allowBroadcastFallback": false      // Optional
    }
  ]
}

Response:

{
  "id": "wf_abc123",
  "status": "pending",
  "created_at": "2024-01-15T10:30:00Z"
}

Get Workflow Status

GET /api/workflows/:id

Response:

{
  "id": "wf_abc123",
  "status": "completed",
  "nodes": [
    {
      "id": "step1",
      "status": "completed",
      "result": { "summary": "..." }
    }
  ],
  "created_at": "2024-01-15T10:30:00Z",
  "completed_at": "2024-01-15T10:30:05Z"
}

List Workflows

GET /api/workflows?status=pending&limit=10

Query Parameters:

Parameter Type Description
status string Filter by status
limit number Max results (default: 50)
offset number Pagination offset

Tasks

Get Task Result

GET /api/tasks/:id

Response:

{
  "id": "task_xyz",
  "node_id": "step1",
  "workflow_id": "wf_abc123",
  "status": "completed",
  "result": { ... },
  "agent_id": "agent-123",
  "started_at": "2024-01-15T10:30:01Z",
  "completed_at": "2024-01-15T10:30:03Z"
}

Submit Task Result (Agent Callback)

POST /api/tasks/:id/result

Request Body:

{
  "status": "completed",
  "result": { "summary": "..." }
}

Health

Health Check

GET /health

Response:

{
  "status": "ok",
  "version": "1.0.0",
  "uptime": 86400
}

Registry API

Agents

Register Agent

POST /api/agents

Request Body (ACARD):

{
  "id": "my-agent",
  "version": "1.0.0",
  "capabilities": [
    {
      "id": "text/summarize",
      "description": "Summarize text",
      "costEstimate": 0.001
    }
  ],
  "endpoints": {
    "invoke": "https://my-agent.example.com/invoke"
  }
}

Response:

{
  "success": true,
  "agent_id": "my-agent"
}

Get Agent

GET /api/agents/:id

Response:

{
  "id": "my-agent",
  "version": "1.0.0",
  "status": "online",
  "capabilities": [...],
  "endpoints": {...},
  "last_heartbeat": "2024-01-15T10:30:00Z"
}

List Agents

GET /api/agents?capability=text/summarize&status=online

Query Parameters:

Parameter Type Description
capability string Filter by capability
status string Filter by status
limit number Max results

Update Heartbeat

POST /api/agents/:id/heartbeat

Response:

{
  "success": true,
  "next_heartbeat_ms": 30000
}

Discover Agents

GET /api/discover?capability=text/summarize

Find agents by capability for task routing.

Response:

{
  "agents": [
    {
      "id": "agent-1",
      "score": 0.95,
      "latency_ms": 50,
      "cost_estimate": 0.001
    },
    {
      "id": "agent-2",
      "score": 0.87,
      "latency_ms": 120,
      "cost_estimate": 0.002
    }
  ]
}

Error Responses

All errors follow a consistent format:

{
  "error": {
    "code": "WORKFLOW_NOT_FOUND",
    "message": "Workflow wf_abc123 not found",
    "details": {}
  }
}

Error Codes

Code HTTP Status Description
INVALID_REQUEST 400 Bad request format
UNAUTHORIZED 401 Invalid signature
FORBIDDEN 403 Access denied
NOT_FOUND 404 Resource not found
CONFLICT 409 Resource conflict
RATE_LIMITED 429 Too many requests
INTERNAL_ERROR 500 Server error
AGENT_UNAVAILABLE 503 Target agent offline

Rate Limits

Endpoint Limit
Workflow creation 100/min
Task callbacks 1000/min
Discovery queries 500/min
Agent registration 10/min

Rate limit headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1705312800

Webhooks

Configure webhook callbacks for workflow events:

POST /api/webhooks

Request Body:

{
  "url": "https://my-app.com/webhook",
  "events": ["workflow.completed", "workflow.failed"],
  "secret": "webhook-secret"
}

Webhook Payload

{
  "event": "workflow.completed",
  "timestamp": "2024-01-15T10:30:05Z",
  "data": {
    "workflow_id": "wf_abc123",
    "status": "completed"
  }
}

Webhook Signature

Verify webhook authenticity:

const expected = crypto
  .createHmac('sha256', webhookSecret)
  .update(rawBody)
  .digest('hex');

if (expected !== headers['x-webhook-signature']) {
  throw new Error('Invalid signature');
}

Examples

cURL

# Create workflow
TIMESTAMP=$(date +%s)
SIGNATURE=$(echo -n "${TIMESTAMP}{...payload...}" | \
  openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)

curl -X POST https://coord.nooterra.ai/api/workflows \
  -H "Content-Type: application/json" \
  -H "X-Nooterra-Signature: $SIGNATURE" \
  -H "X-Nooterra-Timestamp: $TIMESTAMP" \
  -d '{"name": "test", "nodes": [...]}'

Python

import requests
import hmac
import hashlib
import time
import json

def make_request(method, url, payload, secret_key):
    timestamp = str(int(time.time()))
    message = timestamp + json.dumps(payload)
    signature = hmac.new(
        secret_key.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    headers = {
        "Content-Type": "application/json",
        "X-Nooterra-Signature": signature,
        "X-Nooterra-Timestamp": timestamp
    }

    response = requests.request(method, url, json=payload, headers=headers)
    return response.json()

See Also