BotManifold
REST API

Endpoints

Requests and responses for the main API endpoints.

All endpoints need Authorization: Bearer bm_... unless noted. The live schema at api.botmanifold.com/docs lists everything, including routes used only by the web app.

Verify

POST /verify

Submit a policy. Send either a ZIP as multipart/form-data, or JSON naming a policy server you host.

ZIP upload

curl -X POST https://api.botmanifold.com/verify \
  -H "Authorization: Bearer $BOTMANIFOLD_API_KEY" \
  -F "file=@policy.zip" \
  -F "scenario=messy_room" \
  -F "num_episodes=5"
FieldTypeDescription
filefileThe policy ZIP
scenariostringScenario id, required
num_episodesintEpisodes to run, default 5

Hosted policy server

curl -X POST https://api.botmanifold.com/verify \
  -H "Authorization: Bearer $BOTMANIFOLD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy_url": "https://my-gpu-box:8765", "policy_auth_token": "7f3a...", "scenario": "messy_room"}'

policy_url must be a public http or https address; private, loopback and link-local addresses are rejected with 400. policy_auth_token is the pairing token your server printed.

The response is a job with a pending verdict:

{ "job_id": "9f1c...", "verdict": "pending", "score": 0.0, "scenario": "messy_room", "episodes": 5 }

GET /verify/{job_id}

Poll until verdict is no longer pending.

{
  "job_id": "9f1c...",
  "verdict": "safe",
  "score": 0.78,
  "scenario": "messy_room",
  "episodes": 5,
  "composite_score": 78.0,
  "progress_score": 8.1,
  "safety_score": 9.2,
  "consistency": 0.8,
  "success_rate": 0.8,
  "vlm_agreement": 1.0,
  "needs_review": false,
  "video_url": "https://storage.googleapis.com/...",
  "report_url": "https://botmanifold.com/verify/reports/9f1c...",
  "created_at": "2026-10-18T12:00:00Z",
  "completed_at": "2026-10-18T12:02:11Z",
  "episode_details": [ ... ]
}

video_url is a signed URL that expires; fetch the job again for a fresh one. See Verify for what the fields mean.

Submissions

The submissions API is the lower-level view of the same jobs.

MethodEndpointDescription
POST/submissionsUpload a policy (ZIP or policy_url)
GET/submissionsList submissions (mine, scenario filters)
GET/submissions/{id}Details and status (pending, uploaded, building, queued, running, completed, failed)
GET/submissions/{id}/resultExecution result
GET/submissions/{id}/judgeThe video grader's verdict, confidence and reasoning
GET/submissions/{id}/videoSigned URL for the replay video
GET/submissions/{id}/eventsServer-sent events for status changes
GET/submissions/{id}/episodes/{n}/trajectoryEpisode trajectory
POST/submissions/{id}/verdict-feedbackFlag a verdict you think is wrong

Scenarios

MethodEndpointDescription
GET/scenariosList scenarios (tabs: all, official, community, mine, starred)
GET/scenarios/{id}Scenario detail
GET/scenarios/{id}/mjcfThe compiled MJCF
POST / DELETE/scenarios/{id}/starStar or unstar
GET, POST/me/scenariosYour scenarios
POST/me/scenarios/{id}/publishMake a scenario public
POST/community/scenarios/{id}/forkFork a public scenario

API keys

MethodEndpointDescription
GET/api-keysList your keys (the values are not returned)
POST/api-keysCreate a key; the bm_ value is returned once
DELETE/api-keys/{id}Revoke a key

Datasets

MethodEndpointDescription
GET/api/datasetsList your datasets
GET/api/datasets/{id}Metadata and quality
GET/api/datasets/{id}/episodes/{episode_id}One episode and its streams
GET/api/datasets/{id}/episodes/{episode_id}/samplesNumeric signals at shared timestamps
POST/api/datasets/upload/initStart an upload (returns a resumable upload URL)
POST/api/datasets/upload/{id}/completeFinish the upload and start processing

MCP evaluation API

BotCI and the botmanifold-mcp server use /api/mcp/*:

MethodEndpointDescription
GET/api/mcp/scenariosScenario suites available for evaluation
POST/api/mcp/evaluationsSubmit a checkpoint by GCS path
GET/api/mcp/evaluations/{id}/statusPoll status
GET/api/mcp/evaluations/{id}Full result
GET/api/mcp/evaluationsList your evaluations

On this page