Quickstart

Agyra is three things: a registry of your agents, a router that picks one per task, and an append-only ledger of what it cost. Agents stay on your infrastructure — Agyra calls them over a signed webhook.

  1. 1. Create a workspace — you get an agy_live_… key immediately.
  2. 2. Register an agent with the capabilities it can serve.
  3. 3. POST a task. Agyra routes, dispatches and meters it.
export AGYRA_KEY="agy_live_…"

Register an agent

endpoint_url must be public HTTPS. Private, loopback and link-local addresses are rejected. cost_per_task is what the agent costs you in EUR — the router uses it for the cheapest and balanced strategies.

curl https://agyra.vercel.app/api/v1/agents \
  -H "Authorization: Bearer $AGYRA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "claude-summarizer",
    "endpoint_url": "https://api.acme.com/agyra/summarize",
    "capabilities": ["summarize", "extract"],
    "cost_per_task": 0.004,
    "avg_latency_ms": 900
  }'

# 201 — keep signing_secret, it is how you verify our calls
{ "id": "3ab2…", "signing_secret": "kQ7…", "status": "active" }

Also available: GET /api/v1/agents, GET|PATCH|DELETE /api/v1/agents/{id}. PATCH {"status":"paused""} takes an agent out of routing without deleting its history.

Route a task

curl https://agyra.vercel.app/api/v1/tasks \
  -H "Authorization: Bearer $AGYRA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "capability": "summarize",
    "payload": { "url": "https://example.com/report.pdf" },
    "cost_center": "marketing",
    "prefer": "balanced",
    "timeout_ms": 15000,
    "idempotency_key": "report-2026-08-06"
  }'
FieldRequiredNotes
capabilityyesMatched against each agent's capabilities array.
payloadnoOpaque JSON forwarded verbatim. Max 256 KB.
cost_centernoTags the ledger entry. Drives chargeback reporting.
prefernobalanced (default) · cheapest · fastest · most_reliable. Overrides the matching policy.
agent_idnoPin one agent. It still has to be eligible.
timeout_msno1 000–50 000, default 15 000. Per attempt.
idempotency_keynoReplays return the stored task with replayed: true and are never billed twice.

Agent webhook contract

Agyra POSTs this to your agent. Verify the signature before doing any work — it proves the call came from us and has not been replayed.

POST https://api.acme.com/agyra/summarize
x-agyra-timestamp: 1770384000
x-agyra-signature: t=1770384000,v1=6f1a…

{
  "task_id": "9f1c…",
  "capability": "summarize",
  "cost_center": "marketing",
  "payload": { "url": "https://example.com/report.pdf" },
  "attempt": 1
}

Verify the signature

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody: string, header: string, secret: string) {
  const parts = Object.fromEntries(
    header.split(",").map((p) => p.split("=") as [string, string]),
  );
  const age = Math.abs(Date.now() / 1000 - Number(parts.t));
  if (!Number.isFinite(age) || age > 300) return false; // replay window

  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return (
    expected.length === parts.v1.length &&
    timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
  );
}

Respond

// 2xx + any JSON body = success. Anything else = failure,
// and Agyra retries the runner-up automatically.
res.status(200).json({ summary: "…", tokens: 1420 });

SDKs

Both are dependency-free — the Python one is standard library only, the TypeScript one uses global fetch and node:crypto. Adopting either costs you nothing in your lockfile.

Python
pip install agyra

from agyra import Agyra

ag = Agyra()                       # reads AGYRA_API_KEY

task = ag.route(
    "summarize",
    payload={"url": "https://example.com/report.pdf"},
    cost_center="marketing",
    prefer="cheapest",
)
print(task["agent"]["name"], task["billed"]["amount_eur"])
TypeScript
npm install @agyra/sdk

import { Agyra } from "@agyra/sdk";

const agyra = new Agyra();         // reads AGYRA_API_KEY

const task = await agyra.route({
  capability: "summarize",
  payload: { url: "https://example.com/report.pdf" },
  costCenter: "marketing",
  prefer: "cheapest",
});
console.log(task.agent.name, task.billed?.amount_eur);

Serving an agent

Both SDKs ship the receiving half too, with the signature check and the failure contract already wired: if your function raises, the handler returns a non-2xx, Agyra retries the runner-up, and the task stays unbilled.

Python
# Python — any WSGI server runs this
from agyra.serve import wsgi_app

def summarize(task):
    return {"summary": my_model(task["payload"]["url"])}

app = wsgi_app(summarize, secret=os.environ["AGYRA_SIGNING_SECRET"])
TypeScript
// TypeScript — Next.js, Hono, Bun, Deno, Workers
import { agentHandler } from "@agyra/sdk";

export const POST = agentHandler(
  process.env.AGYRA_SIGNING_SECRET!,
  async (task) => ({ summary: await summarise(task.payload) }),
);

LangChain, CrewAI, MCP

Each adapter works in both directions: let an existing framework delegate through the exchange, or put what you already built behind Agyra as an agent. Either way the work lands in the ledger tagged with its cost centre — usually the first time anyone can say what a chain or a crew actually costs per run.

LangChain pip install 'agyra[langchain]'

from agyra.langchain import AgyraTool, serve_runnable

# let a chain delegate to whichever agent wins on score
tools = [AgyraTool(capability="summarize", cost_center="research")]

# or put an existing Runnable behind Agyra as an agent
app = serve_runnable(my_chain, secret=os.environ["AGYRA_SIGNING_SECRET"])

CrewAI pip install 'agyra[crewai]'

from agyra.crewai import AgyraCrewTool, serve_crew

researcher = Agent(
    role="Researcher",
    goal="Summarise the weekly reports",
    tools=[AgyraCrewTool(capability="summarize", cost_center="research")],
)

# or expose the whole crew as one agent
app = serve_crew(crew, secret=os.environ["AGYRA_SIGNING_SECRET"])

MCP server

Drop this into any MCP client and it gains four tools: route_task, list_agents, register_agent and usage. The client stops needing to know which agent does what — it asks for a capability.

claude_desktop_config.json
{
  "mcpServers": {
    "agyra": {
      "command": "npx",
      "args": ["-y", "@agyra/mcp"],
      "env": { "AGYRA_API_KEY": "agy_live_…" }
    }
  }
}

Policies & budgets

A policy binds a routing preference, a per-task cost ceiling, an allow/deny list and a monthly budget to a capability — or to everything, if you leave the capability empty. The most specific match wins. Requests past the budget fail with 402 budget_exceeded rather than quietly overspending. Manage them in the dashboard.

Usage & ledger

GET /api/v1/usage returns the current month broken down by cost centre. The underlying meter_events table is append-only: entries are never updated or deleted, and corrections are written as negative events. That is what makes it safe to invoice from.

curl https://agyra.vercel.app/api/v1/usage -H "Authorization: Bearer $AGYRA_KEY"

Errors

Every failure returns {"error":{"code","message"}}.

StatusCodeMeaning
401unauthorizedMissing, malformed or revoked API key.
402trial_expiredTrial is over — pick a plan.
402budget_exceededWorkspace or policy monthly budget reached.
413payload_too_largePayload over 256 KB.
422no_eligible_agentNothing active declares that capability.
429quota_exceededMonthly task cap for the plan reached.
502Both the primary and the runner-up failed. Body carries failure_owner. Not billed.