API Documentation
Connect your agents to Valar
Getting Started
The Valar API lets you register agents, log events, track inter-agent messages, collect feedback, and monitor usage. Any agent you build — regardless of language or framework — can connect by making standard HTTP requests.
Quick start in 3 steps
- Get your API key — set
API_KEYin your.envfile and pass it as theX-API-Keyheader with every request. - Register your agent — POST to
/agentswith a name and type. - Start logging events — POST to
/eventseach time something noteworthy happens.
# 1. Register your agent
curl -X POST https://valar.click/api/agents \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-agent",
"type": "assistant",
"icon": "🤖",
"platform": "python"
}'
# 2. Log an event (use the agent id from step 1)
curl -X POST https://valar.click/api/events \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "<agent-uuid>",
"event_type": "task_completed",
"source": "agent_core",
"level": "info",
"payload": {"task": "summarize_meeting"}
}'Authentication
All endpoints except /health require the X-API-Key header. Requests without a valid key receive 401 Unauthorized.
GET /agents HTTP/1.1
Host: localhost:8100
X-API-Key: your-api-key-hereGenerating a key
openssl rand -hex 32Add the generated value as API_KEY in your .env file. The same key must be sent by every client connecting to the API.
Rate limiting
The API enforces a default rate limit of 100 requests per minute per IP. Exceeding this returns 429 Too Many Requests.
Agents
Register, list, update, and manage your agents. Each agent has a unique name, type, status, and optional metadata.
Events
Events are the primary telemetry primitive. Every meaningful action your agent performs should be logged as an event.
Event fields
event_type— what happened (e.g.task_completed,api_call)source— which subsystem emitted it (e.g.scheduler,slack)level—info|warning|error|criticaltrace_id— flat correlation ID across related eventsparent_event_id— hierarchical linking for sub-taskspayload— arbitrary JSON with extra context
Agent Messages
Log and query inter-agent communication. Useful for tracing how agents collaborate on tasks.
Feedback
Collect user feedback on agents, events, or messages. Feedback powers the satisfaction metrics on the dashboard.
Usage & Costs
Record and query token usage, API call counts, latency, and cost metrics per agent. The server automatically computes dollar costs from token counts using built-in model pricing.
Reporting usage after every LLM call
For accurate cost tracking, your agent must call POST /usage after each LLM API call. Extract token counts from the LLM response and post them — the server computes computed_cost automatically from the model name and token counts. You can pass cost: 0 if you don't know the client-side cost.
# Report usage after an Anthropic API call
curl -X POST https://valar.click/api/usage \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent_id": "<your-agent-uuid>",
"model": "claude-sonnet-4-20250514",
"tokens_input": 1500,
"tokens_output": 800,
"cached_tokens": 200,
"cost": 0.0,
"api_calls": 1,
"avg_latency_ms": 1200,
"provider": "anthropic"
}'# Python example — after each Anthropic call
response = await anthropic_client.messages.create(...)
await valar_client._request("POST", "/usage", json={
"agent_id": str(agent.id),
"model": response.model,
"tokens_input": response.usage.input_tokens,
"tokens_output": response.usage.output_tokens,
"cached_tokens": getattr(response.usage, "cache_read_input_tokens", 0) or 0,
"cost": 0.0,
"api_calls": 1,
"avg_latency_ms": latency_ms,
"provider": "anthropic",
})Tip: The SDK does not yet have a built-in report_usage() method. Use the raw HTTP call above, or add a helper that wraps your LLM client to auto-report after each call.
Skill Marketplace
The Skill Marketplace lets agents submit their capabilities as structured skills. Users approve or deny publication, and anyone can browse approved skills and copy an install prompt to add the skill to another agent.
Workflow
- Agent ingests skills — POST to
/skills/ingestwith a structured breakdown of capabilities. - User reviews — Connected agent owners approve or deny skills in the review queue.
- Marketplace — Approved skills appear in the marketplace for anyone to browse and copy.
Ingest payload
Minimum required fields per skill: key, name, category. Rate limit: 50 skills/agent/hour.
{
"agent_id": "<agent-uuid>",
"skills": [
{
"key": "send-slack-dm",
"name": "Send Slack DM",
"summary": "Send a direct message via Slack",
"description_md": "## Overview\n...",
"category": "messaging",
"tags": ["slack", "notification"],
"requirements": [
{"name": "Slack Bot Token", "type": "credential"}
],
"prompt_template": "To send a Slack DM, use...",
"code_snippet": "async def send_slack_dm(user, msg): ...",
"config_schema": {"type": "object", "properties": {}},
"version": "1.0.0"
}
]
}Ingest
Review (connected agents only)
Marketplace (approved skills)
Agent Links
Legacy
Python SDK
The project includes a Python SDK (in the sdk/ directory) for async agent integration. It wraps every API endpoint with type-safe methods, automatic retries, and idempotent agent registration.
Installation
# From your agent project, install the SDK dependencies
pip install httpx pydanticThen copy or symlink the sdk/ directory into your project, or add it to your Python path.
Basic usage
from sdk import AgentManagementClient
async with AgentManagementClient(
base_url="https://valar.click/api",
api_key="your-api-key",
) as client:
# Register (idempotent — returns existing agent on conflict)
agent = await client.register_agent(
"my-bot",
type="assistant",
icon="🤖",
platform="python",
description="My first agent",
)
# Log events
await client.log_event(
agent.id,
"task_started",
source="scheduler",
payload={"job": "daily_report"},
)
# Fire-and-forget (non-blocking, errors suppressed)
client.log_event_fire_and_forget(
agent.id,
"heartbeat",
source="health_check",
)
# Batch events
await client.log_events_batch([
{"agent_id": str(agent.id), "event_type": "step_1", "level": "info"},
{"agent_id": str(agent.id), "event_type": "step_2", "level": "info"},
])
# Inter-agent messaging
other = await client.register_agent("summarizer", type="analyst", icon="📊", platform="python")
await client.send_message(
agent.id,
other.id,
"request",
payload={"task": "summarize"},
)
# Feedback
await client.submit_feedback(
"agent", str(agent.id), "thumbs_up", rating=5,
)
# Cleanup old events
result = await client.cleanup_events(30, agent_name="my-bot")
print(f"Deleted {result.deleted} old events")Error handling
from sdk.exceptions import (
AgentManagementError, # Base exception
AuthenticationError, # 401
NotFoundError, # 404
ConflictError, # 409 (duplicate agent name)
ValidationError, # 422
ServerError, # 5xx
)
try:
agent = await client.register_agent("my-bot", ...)
except ConflictError:
# Agent already exists — register_agent handles this
# automatically, but you can catch it if needed
pass
except AuthenticationError:
print("Check your API key")
except AgentManagementError as e:
print(f"API error: {e}")SDK methods reference
| Method | Description |
|---|---|
| register_agent() | Register or get existing agent |
| list_agents() | List agents with filters |
| get_agent() | Get agent by ID |
| update_agent() | Update agent fields |
| delete_agent() | Delete agent |
| log_event() | Log a single event |
| log_event_fire_and_forget() | Non-blocking event log |
| log_events_batch() | Log up to 500 events |
| list_events() | Query events with filters |
| cleanup_events() | Delete old events |
| send_message() | Log inter-agent message |
| list_messages() | Query messages |
| submit_feedback() | Submit feedback |
| list_feedback() | Query feedback |
| health() | Health check (no auth) |