Sidekick Robotics, Inc.
World models, vision-language-action policies and embodied reasoning behind a single endpoint. One key, one balance, one request shape. Sidekick picks the model and the provider that fit your latency budget, action space and price ceiling, and falls past whichever one is down.
Install with pip install sidekick-sdk
Physical AI does not fit one verb. A model that imagines the next second of video and a model that emits joint targets are different products, so they are different endpoints rather than one endpoint that returns whatever the backend happened to produce.
POST /v1/predict
Roll the world forward. Observations in, predicted frames out.
POST /v1/act
Observations in, an action chunk out, in a declared action space.
POST /v1/ground
Embodied reasoning. Where is the mug, what is graspable, which way to the drawer. Served live by Gemini Robotics ER 2. Points and boxes normalised 0 to 1, never actions: coordinates executed as joint targets would move the wrong way.
POST /v1/evaluate
Score a policy inside a world model against a registered benchmark.
Ask for a job, not a checkpoint. sidekick/auto:manipulation is a
router alias: Sidekick picks whichever manipulation policy and pool fit, and the response tells you
which one answered. This is a real exchange, and it is one where the first choice did not answer.
1 Send this
2 Get this back
{
"id": "req_29e72634fd584a87b801",
"object": "world.action",
"model": "physical-intelligence/pi-0",
"action": {
"space": "joint_pos_14",
"steps": [
[ 0.0614, -0.0042, -0.0120, -0.0567, ..., 0.5865],
[ 0.0672, -0.0008, -0.0104, -0.0579, ..., 0.5878],
...
],
"dt_ms": 66,
"note": "4 steps, 14 joint targets each: 7 per arm"
},
"route": {
"model": "physical-intelligence/pi-0",
"region": "us-east",
"precision": "bf16",
"attempts": [
{ "model": "physical-intelligence/pi-0-5",
"status": "error", "latency_ms": 30188,
"reason": "upstream did not answer within 30s" },
{ "model": "physical-intelligence/pi-0",
"status": "ok", "latency_ms": 684 }
],
"fallback_used": true,
"simulated": false
},
"usage": {
"action_steps": 4, "gpu_seconds": 0.6844,
"cost_usd": 0.005416
}
}
The caller named a job, not a checkpoint. The router tried π0.5 first, that pool did
not answer inside its 30-second budget, so it fell past to π0 and had an answer 684 ms later.
The client retried nothing and knew neither model name in advance. route.attempts is the
audit trail and it includes the failure rather than hiding it. simulated is the honesty
flag: true means placeholder output rather than a model prediction, so you can never
mistake one for the other. usage.cost_usd is what came off your balance, and it covers the
call that succeeded.
One field. You are not tuning a router, you are stating a priority, and the router turns that into an ordering over every model and pool that can serve your request.
{ "model": "sidekick/auto:manipulation", "preference": "fastest" }
Spread load across healthy pools, weighted toward the cheaper ones.
When you have no strong opinion. Not a sort: the absence of one.
Lowest measured latency first, not the advertised p50.
Closed-loop control, where 100 ms is a deadline and not a preference.
Lowest cost per action step or frame.
Batch rollouts, data generation, evaluation sweeps. Nothing is waiting.
Highest uptime and precision, price ignored.
Production traffic where a retry costs more than the call.
Three forms, and three places to state a priority. If you write more than one, the narrower one wins.
physical-intelligence/pi-0
An exact slug. This checkpoint, whichever pool serves it best.
sidekick/auto:manipulation
A router alias. Name the job and let the router pick the checkpoint.
pi-0-5:turbo
A variant suffix: :nitro throughput, :floor price,
:turbo latency, :quality precision.
So {"model": "physical-intelligence/pi-0-5:turbo", "preference": "cheapest"}
routes for latency: the suffix is attached to the model you named, so it outranks the preference you
set for the request.
One call. The top level says what you want; the
provider block says how to choose who serves it. Nothing here is required
except model and observations.
POST /v1/act
Idempotency-Key: ep-8f21-step-014
{
"model": "sidekick/auto:manipulation",
"preference": "fastest",
"instruction": "put the spoon on the towel",
"action_space": "ee_delta_6d_grip",
"horizon": 16,
"observations": [{
"frames": [{"camera": "primary", "url": "https://..."}],
"proprio": [0, 0, 0, 0, 0, 0, 0]
}],
"provider": {
"objective": {"latency": 0.7, "price": 0.3},
"deadline_ms": 200,
"max_cost_usd": 0.05,
"min_uptime_30d": 0.995,
"session_id": "ep-8f21",
"hedge": {"after_ms": 80},
"data_collection": "deny"
}
}
Idempotency-Key makes a retry return the first answer instead of a second, different future. These models are stochastic, so a naive retry bills twice and moves the robot twice.
action_space is a contract, not a hint. A policy that emits a different dimensionality is refused rather than reshaped, because the alternative is a robot moving along the wrong axes with nothing in the response to say so.
provider is the whole control surface, applied in the order below. Send none of it and you still get live-only routing, fallback and circuit breaking.
modelpreferenceaction_spacehorizonmodelsallow_simulatedonlyignoreregiondata_collectionmax_latency_msmin_uptime_30dmax_cost_usdordersortobjectivesession_idallow_fallbacksdeadline_mshedgeroute.attemptsroute.simulatedusage.cost_usdOrdering is on measured latency, so a pool whose real traffic disagrees with its advertised p50 is demoted rather than believed. The terminal below runs this planner against live supply for free, and lists every field in full.
The same API, tuned to what is actually waiting on the answer.
A robot is moving. Late is the same as wrong.
"provider": {
"objective": {"latency": .8, "reliability": .2},
"deadline_ms": 150,
"hedge": {"after_ms": 80},
"session_id": "ep-8f21",
"min_uptime_30d": 0.995
}
Hedge the tail, hold the policy steady for the episode, and fail fast rather than answer late.
Nothing is waiting. Volume is the cost.
"provider": {
"sort": "price",
"max_cost_usd": 0.02,
"allow_fallbacks": true
}
Cheapest first, a ceiling on each call so a long horizon cannot surprise the invoice, and no hedging: paying twice to save milliseconds nobody is waiting on is waste.
Someone else's data, and an auditor.
"provider": {
"only": ["modal-sidekick-2"],
"region": ["us-east"],
"data_collection": "deny",
"allow_fallbacks": false
}
Pin the pool you have contracted, keep frames in one jurisdiction, and refuse a substitution rather than serve one silently.
Every field above is enforced by the router and previewable for free: the terminal below runs this exact planner against live supply and shows you the plan it would call, without calling anything. Full reference with worked examples in the API section.
Every world model in Awesome-World-Models, normalized across five domains: a stable slug, the contracts it serves, the embodiments and action spaces it speaks, and which providers will run it. Benchmarks and survey papers are catalogued separately, because they are not models and are never routable.
Every entry by domain and by how far along it is toward being servable. The routable column is what a developer can call today. Counts include the policy and embodied reasoning models below, which are tracked here because they are what most developers reach for, and labelled because they are not world models: a policy has no generative video head, and a reasoner returns neither frames nor joint targets.
The source list's own taxonomy, preserved. Each family is addressable as a router alias
(sidekick/auto:manipulation) so callers name a job rather than a checkpoint.
Who can serve these models, and at what cost and latency. Median price is across every offering that provider carries.
| Provider | Kind | Models | Median $/frame | p50 | Throughput | Max horizon | Uptime 30d |
|---|
Search by name, paper title or slug. Every row links back to its source.
| Model | Domain | Family | Status | Contracts | Rate | Source |
|---|
The benchmark registry: what POST /v1/evaluate runs a policy against.
Passing an unregistered scenario is rejected before the job is queued and billed.
| Benchmark | Targets | Metrics | Status | Year | Source |
|---|
Surveys, position papers, theory and tutorials. These have no servable artifact. They are catalogued so the map is complete, and kept out of the model namespace so a survey is never published as a callable checkpoint.
| Entry | Kind | Section | Year | Source |
|---|
Every endpoint, with the fields that matter. The full interactive reference with request bodies, schemas and a "Try it" button lives at /docs; the machine-readable spec is at /openapi.json.
One bearer token per key. Keys are scoped and can be limited to specific models, a workspace budget and a rate limit.
Authorization: Bearer sk-sidekick-...
Never put a key in browser JavaScript. Call Sidekick from your own server, or use the server-side proxy pattern in the SDK. A key in a client bundle is a key on someone else's machine.
| Endpoint | Takes | Returns | Billed on |
|---|---|---|---|
POST /v1/predict |
observations, horizon |
predicted visual future | frames out |
POST /v1/predict/stream |
same | SSE: route, frame×N, done |
frames out |
POST /v1/act |
observations, instruction, action_space |
an action chunk | action steps |
POST /v1/ground |
observations, instruction |
points and boxes, normalised 0–1 | tokens |
POST /v1/evaluate |
policy_endpoint, scenario, episodes |
a job id, then scores | episodes |
Four contracts rather than one because the outputs are not interchangeable. A world model rolls video forward, a policy emits joint targets, a reasoner returns image coordinates. Collapsing them into one endpoint would let a caller execute pixel coordinates as joint targets, and nothing in the response would say so.
The model field takes three things, and a
provider block steers the choice within them.
| Form | Example | Meaning |
|---|---|---|
| Exact slug | physical-intelligence/pi-0 |
this checkpoint, any provider that serves it |
| Router alias | sidekick/auto:manipulation |
name the job, let the router pick the checkpoint |
| Variant suffix | nvidia/gr00t-n1-7:nitro |
:nitro throughput, :floor cheapest, :turbo latency |
"provider": {
"order": ["modal", "baseten"], // try these first, in this order
"only": ["modal"], // or restrict to these entirely
"ignore": ["fal"], // never route here
"sort": "price", // price | throughput | latency
"max_latency_ms": 150, // hard deadline; providers over it are skipped
"allow_fallbacks": true, // false means fail rather than substitute
"data_collection": "deny", // skip providers that retain your frames
"require_parameters": true // skip providers that would drop seed, etc.
}
GET /v1/routes lists every alias and variant. GET /v1/models is the whole registry as JSON, filterable by domain, contract, embodiment and action space.
| Feature | How |
|---|---|
| Automatic fallback | Providers are attempted in plan order; every attempt is returned in
route.attempts so you can see what happened. |
| Circuit breaking | A provider that fails repeatedly is skipped until it recovers.
GET /v1/status shows the state. |
| Idempotent retries | Send Idempotency-Key (header or body). A retry returns the original
response and bills once, which matters because these models are stochastic and a
naive retry returns a different future. |
| Free dry run | POST /v1/routes/preview returns the plan and an estimated cost without
running anything. |
| Honesty flag | Every response carries route.simulated.
true means placeholder output, not a model prediction. |
| Endpoint | What it does |
|---|---|
GET /v1/billing/balance | credits and lifetime spend |
POST /v1/billing/topup | returns a Stripe Checkout URL |
GET /v1/usage | per-request ledger and totals |
GET /v1/key | the calling key: scopes, budget, rate limit |
GET /v1/runtimes | wire protocols, and which offerings are real |
GET /v1/status | circuit-breaker state, jobs, cache |
GET /health | deployment config, warnings, live providers |
Everything an account needs: a balance, credits, keys and a dry run of the router. It talks to this API from your browser with your own key, so nothing here is a mock.
Paste a Sidekick API key. It is held in this tab's memory only, never written to storage
and never sent anywhere except this API, because a key in localStorage is readable by
every script that ever runs on this origin.
No key yet? Accounts are provisioned by the Sidekick team while the API is in preview. Ask for one, then come back here to top up.
One balance covers every model and every provider. Prepaid rather than metered on purpose: a rollout that runs long is not fraud, and a prepaid balance means the gateway refuses work with a 402 before renting a GPU instead of sending you an invoice you did not expect.
What this is: when you send a request, Sidekick does not call one
fixed model. It builds a ranked plan of model-and-provider pairs that satisfy your constraints, calls
the first, and falls to the next if that one errors or times out. This runs exactly that planner and
shows you the list, without calling any model. Nothing is billed, so it doubles as a pricing
calculator. Change the preference and watch the order change; the same planner answers your
/v1/act calls.
Two prices, and the gap between them is the point. List is the published rate for the horizon you set. Now is what this call would actually cost at this moment, and it is higher only when the container is scaled to zero, because waking a GPU costs real money and so does the minute it stays warm afterwards. We charge that to the request that caused it rather than spreading it across everyone. A call inside a running control loop extends the warm window by its own duration and prices at list, so the two numbers are the same. Press the button twice in a row and watch the second one drop.
The three dropdowns above set model, the contract, and
preference. A real call can say a great deal more, and all of it is enforced by the
same planner this terminal runs. The stage each field acts at is
described above; this is the whole list in one place. A hard
constraint removes candidates from the plan, a soft one only reorders what survived. When
constraints leave nothing, the request fails with 409 no_route_available and names
every offering it dropped and why, rather than quietly relaxing one.
| Field | What it does | |
|---|---|---|
sort | soft | One axis: price, latency, throughput,
quality. |
objective | soft | Several axes at once, weighted, e.g.
{"latency":0.6,"price":0.3,"reliability":0.1}. Each axis is
normalised before the weights apply, so only the ratios matter. A stated
objective is answered deterministically; the default is a weighted shuffle
that spreads load. Setting it alongside sort is a 422. |
order / only / ignore | hard | Pin the provider order, restrict to a set, or exclude one. order
with allow_fallbacks:false is the strong form. |
session_id | soft | Pin an episode to the checkpoint and provider that served its first call. Switching policy mid-episode changes the action distribution discontinuously. Promotion only: a pin never routes around a constraint you set, and it expires after 15 minutes of silence. |
max_latency_ms | hard | Drop providers whose advertised p95 exceeds it, before anything runs. |
deadline_ms | hard | The real clock across the whole request, fallbacks included. A step the router does not expect to finish in the time left is skipped rather than started. A control loop is better served by a fast error at 200 ms than a correct answer at 600 ms. |
max_cost_usd | hard | Ceiling on this call's bill, priced against the horizon you set. The per-unit ceilings below bound a rate; this bounds the total. |
max_price_per_framemax_price_per_action_step |
hard | Per-unit ceilings. Frames bind on predict, action steps on
act, so a ceiling on one does nothing to the other. |
min_uptime_30d | hard | Reliability floor, e.g. 0.995. |
region / data_collection | hard | Data residency, and dropping providers that retain frames. |
hedge | soft | {"after_ms":80} dispatches a second provider when the first is
late and takes whichever answers. You pay for both, itemised as
route.hedge_cost_usd: a remote GPU cannot be recalled. |
allow_simulated | hard | Off by default. On, the plan may include catalogued offerings with no live
deployment, which return structurally valid placeholder output. Every such
response carries route.simulated: true. |
Full guide with worked examples: the API reference
and docs/ROUTING.md.