Factor API

Run a real robot Shift.

Use the console to create a Teleoperator and register a robot. The robot receives one credential. Send that credential only from the robot adapter.

Four objects

Teleoperator. A persistent named worker with one Supervisor brain, instructions, allowed skills, Handoff rules, and immutable revisions.

Robot. A registered machine and adapter with a local safe hold, watchdog, and local control authority.

Shift. One Teleoperator assigned to one connected robot for bounded work. This is the live and billing object.

Handoff. A transfer of responsibility for the next decision between the Operator, Supervisor, and human. Safety authority never transfers.

1. Register in the console

Create a Teleoperator, select one of Factor's six brains, and list the skills it may call. Then connect a robot. Factor shows the robot token once. Store it on the robot, not in browser code.

2. Send a heartbeat

curl https://factor.ac/v1/factor/robots/ROBOT_ID/heartbeat \
  -H "Authorization: Bearer $FACTOR_ROBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"status":"ready","capabilities":{"camera":true}}'

The robot is connected while its authenticated heartbeat is less than two minutes old. A Shift cannot start on stale connectivity.

3. Ask the Teleoperator

curl https://factor.ac/v1/factor/shifts/SHIFT_ID/supervise \
  -H "Authorization: Bearer $FACTOR_ROBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "robot_id":"ROBOT_ID",
    "instruction":"Clear the blocked pickup and continue",
    "state":"safe hold; gripper open; tote visible",
    "images":["data:image/jpeg;base64,..."]
  }'

The response is a bounded Supervisor decision under the exact brain and Teleoperator revision pinned when the Shift started. The local stack decides whether to execute any skill call.

4. Record evidence

curl https://factor.ac/v1/factor/shifts/SHIFT_ID/events \
  -H "Authorization: Bearer $FACTOR_ROBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "robot_id":"ROBOT_ID",
    "kind":"local_rejection",
    "payload":{"skill":"retry_grasp","reason":"force limit"}
  }'

Valid kinds are task, observation, decision, action, local_rejection, outcome, and note. Factor never invents an outcome.

5. Hand off

Calling /supervise records an immediate Operator-to-Supervisor transfer. When the onboard Operator takes the next decision again, post a Supervisor-to-Operator Handoff. AI-to-AI transfers resolve immediately and stay billable. Human transfers remain open until a person resolves them in the console.

curl https://factor.ac/v1/factor/shifts/SHIFT_ID/handoffs \
  -H "Authorization: Bearer $FACTOR_ROBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "robot_id":"ROBOT_ID",
    "from":"supervisor",
    "to":"human",
    "reason":"Occluded grasp after two bounded retries",
    "safe_hold":true,
    "robot_state":{"mode":"safe_hold"}
  }'

A human Handoff requires explicit safe-hold confirmation. It pauses Supervisor inference and the Factor robot-hour meter until resolved in the console.

Control boundary

Factor owns task-level reasoning and Handoff state. The customer's onboard executor owns transforms, rate limits, collision checks, reflexes, watchdogs, emergency stops, safety, and actuators. A cloud response is never direct motor authority.