Control plane reference
Every /v1 endpoint, typed, on shimmy.control.
const savings = await shimmy.control.savings();
const calls = await shimmy.control.calls({ limit: 50 });
const graph = await shimmy.control.agentGraph(agentId); Savings and activity
| Method | Returns |
|---|---|
savings() | Totals, split by source: cache, routing, TTC, trace |
statement(from, to) | A billing period, with fee_rate and amount_due |
calls({ agent, limit }) | Per-call optimization detail — the curated view |
activity({ limit }) | The raw metered timeline |
calls() and activity() are different shapes over related data. The two
endpoints predate each other and disagree; both are exposed named for what they
are rather than hidden behind a lossy union. Prefer calls().
Proxy agents
Your own code, routing through the edge.
| Method | Notes |
|---|---|
listAgents() | With per-agent savings |
createAgent(name) | Response carries the only copy of the key |
createAgentKey(id) | An additional key |
agentGraph(id) | The inferred run structure |
agentGraph fidelity depends on instrumentation: calls that declared a parent
produce the real call tree, calls that did not are read as a linear chain —
right for a sequential agent, wrong for a parallel one.
Discovery mode
The per-step model search on platform keys. These are HTTP routes (no SDK wrappers yet); the dashboard’s agent page drives them.
| Route | Notes |
|---|---|
PUT /v1/proxy-agents/:id/discovery | {enabled: bool} — the toggle, read back after write |
GET /v1/proxy-agents/:id/discovery | Live progress: derived state, credit, every step seen |
GET /v1/proxy-agents/:id/discovery/report | Settled answers, priced deltas, reachability vs current keys |
An agent discovers when three things agree: its discovery_enabled flag, a
request that asks (model: "discover", a step.mode: "discover" annotation,
or "auto" while the flag is on), and credit remaining. The agent state is derived at read time — discovering while any seen step is unsettled, optimized when all are — so a newly-seen step flips it on its own.
Managed agents
Workflows the platform runs for you. Kept on separate methods from proxy agents deliberately — the API calls both “agents”, and collapsing them would hide which product a call belongs to.
| Method | Notes |
|---|---|
listManagedAgents() | |
createManagedAgent(...) | kind is validated server-side |
startRun(agentId) | 402 when the run cap is exhausted; the body carries cap and used |
runPlayground(id, jobConfig) | Custom input; validated before a run is spent |
executeMove(id, spec) | Execute one proposed action |
getRun(runId) | |
runEventsUrl(runId) | See below |
Settings
| Method | |
|---|---|
captureSettings() / setCaptureSettings() | Content capture and retention |
guardSettings() / setGuardSettings() | PII redaction, injection policy |
routingSettings() / setRoutingSettings() | Ladders, band, tiebreak, learning mode |
Routing writes are validated locally first — see config as code for why that matters more than it sounds.
Connections
listConnections(), putWordPress(...), deleteWordPress(). Secrets are never
returned. Hosts are validated server-side: localhost, .local, loopback and
private ranges are rejected, since a stored connection is dialed from our
infrastructure.
Unauthenticated
Signup is how you get a key, so these are standalone functions rather than methods on a class you cannot construct yet.
import { signup, estimate } from '@rfa-labs/shimmy';
const { api_key } = await signup({ company: 'Acme', email: 'dev@acme.com' });
const projection = await estimate({ monthly_spend: 5000 }); estimate() prices a hypothetical, not your traffic — and deliberately
under-claims, so the live meter tends to beat it rather than miss it.
login() / logout() exist for browser session auth (they set and clear the
session cookie the dashboard uses). Server-side integrations authenticate with the sk-opt-… key on every request instead and never need them.
Errors
Every failure raises a typed error carrying status, endpoint, message and
the raw body. The SDK normalizes three things the API does inconsistently:
three different error body shapes, HTML returned for unknown paths (the SPA
fallback, which would otherwise surface as a JSON parse error), and the two call
representations above.