Documentation menu

Connect your endpoint

Keep weights on your own infrastructure — the facility streams observations to your HTTPS URL and logs round-trip time per step.

Your endpoint

Endpoint mode inverts the trust arrangement of the other two packagings: your weights never enter the facility. You host inference; the cell streams observations to your URL and expects actions back, per step, on a declared latency budget. What you give up is the network — it is now inside the control loop — and much of this page is about being honest with yourself about that.

Prerequisites

  • An HTTPS inference URL reachable from the facility's egress.
  • Capacity for the declared action rate. joint_delta_50hz is an action every 20 ms, sustained for every episode of the run — provision for the whole job, not for a demo.
  • Your own version identity. Put the deployment version in the URL path or hostname — https://inference.acme.ai/v7/act — because the run records the URL. That is how a result stays attributable to a deployment: if v7 and v8 share one URL behind a load balancer, no artifact can say which one earned the rate.

The protocol, honestly

The policy object carries three fields — url, latency_budget_ms, fallback — and nothing else. There are no auth headers, bearer tokens, or mTLS fields today. Treat the URL as the credential: make it unguessable and per-run (https://inference.acme.ai/v7/act/8f3a2c91d4e6), rotate it after the run, and enforce your own network controls — allowlists, WAF rules — on your side. Do not assume any facility-side security guarantee beyond "the URL is stored with the run".

The interface itself is behavioral: the cell runtime feeds your server the observations named by the declared observation_contract and expects actions in the declared action_space, at its declared rate. Between episodes the runtime signals an episode boundary, and your server clears its per-episode state — physical scene reset is the cell's job (scripted or teleop-assisted), never your policy's. A formal wire-level spec — routes and schemas — is not yet published.

What leaves the cell

Exactly the feeds named by the declared observation_contract, plus the proprioception schema — per step, to your URL. droid-3cam means three RGB views and joint state, and nothing else. Round-trip time is logged per step to /events. In return, nothing is cached: endpoint mode creates no Roborama copy of your weights at all — the same IP posture the data contract applies to your episodes.

Latency and the fallback

Your network is in the loop, so the budget is explicit: latency_budget_ms=80 means any step whose round trip exceeds 80 ms triggers the declared fallback. "halt" freezes the arm and ends the episode, which lands in its own cluster instead of polluting the physics statistics; "teleop" is the other documented value. Persistent unreachability fails the run with policy_endpoint_timeout. Budget from your p99, not your median — the policies page shows the arithmetic of a 40 ms median with a 200 ms p99, and it is not on your side.

Connect

connect a hosted endpoint
import roborama  # reads ROBORAMA_API_KEY from the environment

policy = roborama.Policy.endpoint(
    url="https://inference.acme.ai/v7/act",
    latency_budget_ms=80,
    fallback="halt",
)

run = roborama.run(
    robot="g1-edu-pro@fw2.3",
    environment="kitchen-std@v1.2",
    policy=policy,
    task="load_dishwasher@v2",
    episodes="auto(ci=0.95, moe=0.03)",
    max_budget_usd=4000,
)

result = run.result()
# per-step endpoint RTT is logged to /events for this run
print(run.id, result.success_rate, result.ci95)

Validate

Local first: ROBORAMA_MOCK=1 exercises the full loop against packaged fixtures — no API key, no charge.

dry-run in mock mode
import roborama

# Mock mode: no API key, no hardware. The whole loop runs
# offline against packaged fixtures — or set ROBORAMA_MOCK=1.
client = roborama.Client(mock=True)

quote = client.quote(
    robot="aloha2-pro",
    environment="cell-a",
    episodes=300,
)
print(quote)
# {robot_hours: 10.0, env_hours: 10.0, usd: 860, queue_eta: "2h"}

run = client.run(
    robot="aloha2-pro@fw1.1",
    environment="cell-a@v1.0",
    policy=roborama.Policy.checkpoint(
        hf="acme/act-so101-pick-v2",
        runtime="lerobot",
    ),
    task="pick_place@v1",
    episodes=300,
    max_budget_usd=1000,
)
print(run.result())
# n=300  rate=0.843  ci95=(0.797, 0.881)

At submission, the declared contracts are validated server-side; a mismatch is contract_validation_failed (422), and a rejected submission costs nothing. Then, at cell startup, the runtime performs a reachability exercise against your URL before episode 1: sustained failure lands as policy_endpoint_timeout, and no episodes bill. A dead DNS record costs you a queue slot, not money.

Quote

Endpoint runs meter like any other — robot-hours and environment-hours; your inference compute stays on your own bill. Quote first, and read the queue ETA as a capacity question: can the deployment hold the declared rate for that long? (billing & budgets)

quote before you run
import roborama  # reads ROBORAMA_API_KEY from the environment

quote = roborama.quote(
    robot="g1-edu-pro",
    environment="kitchen-std",
    episodes=600,
)
print(quote)
# {robot_hours: 20.0, env_hours: 20.0, usd: 3740, queue_eta: "6h"}

Evaluate

Submission is an ordinary run(). Watching live matters more here than in the other packagings — per-step RTT lands in /events as it happens, so you can catch a saturating deployment while the run is still cheap to stop:

watch it live
import roborama  # reads ROBORAMA_API_KEY from the environment

run = roborama.runs.get("run_8842")

for event in run.watch():   # live: episode ticker + WebRTC stream URLs
    print(event.episode, event.status)

stream = roborama.streams.get("cell-g1-04")
print(stream)
# {webrtc: "wss://streams.roborama.com/cells/cell-g1-04/webrtc",
#  mjpeg: "https://streams.roborama.com/cells/cell-g1-04/mjpeg",
#  viewer_token: "vt_7Kq2mHentXw4"}

Inspect results

Alongside n, the rate, and the Wilson interval, the episode record is where endpoint mode's questions get answered: halted episodes carry their own cluster, and the /events channel holds the per-step RTTs, so a latency problem and a policy problem are distinguishable after the fact. run.report(format="pdf") cites the same record — channels and retention are in the data contract.

Compare versions

v7 against v8 is two URLs under the same declared configuration — which is why the version belongs in the URL. Submit both to compare() for paired episodes: same scenes for both deployments, roughly half the episodes, and a verdict with an interval on the difference.

Troubleshoot

CodeSymptomFix
policy_endpoint_timeoutrun halted — steps persistently over latency_budget_ms, or the startup reachability exercise failedbudget from your p99, not your median; provision capacity for the declared rate sustained, not burst; fix the endpoint, then resubmit
contract_validation_failed422 at submission; nothing ranthe declared action_space or observation_contract doesn't match the pinned robot and scene
estop_triggeredrun stopped by a hardware or safety emergency stopthe episode is marked estop, the cell is inspected, partial results are kept — contact support if unexpected
budget_exceededrun halted at max_budget_usd; partial results keptraise the cap and resubmit if the interval is too wide

Where next

  • Policies — the three packagings, and the latency callout this page keeps pointing at.
  • Data contract — the IP posture endpoint mode is built on.
  • Run your container — the opposite trade: ship the image, take the network out of the loop.
  • Error codespolicy_endpoint_timeout in the full catalogue.