Skip to content

API Endpoints

Detailed documentation for all REST API endpoints.

All requests require Authorization: Bearer <api_key> header.


Verify (Primary API)

Submit Verification

Submit a policy for safety verification.

POST /verify

Content-Type: multipart/form-data

Parameters:

Name Type Required Description
policy file Yes* Zip file containing policy.py
policy_url string Yes* URL to a running policy server
scenario string Yes Scenario ID
num_episodes integer No Number of evaluation episodes (default: 3)

*Either policy (file upload) or policy_url must be provided.

Example:

curl -X POST https://api.botmanifold.com/verify \
  -H "Authorization: Bearer $BOTMANIFOLD_API_KEY" \
  -F "policy=@policy.zip" \
  -F "scenario=messy_room"
from botmanifold import BotManifoldClient

client = BotManifoldClient(api_key="bm_...")
report = client.verify.run("policy.zip", scenario="messy_room")

Response (201 Created):

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "QUEUED",
  "scenario": "messy_room"
}

Get Verification Status

GET /verify/{job_id}

Response (200 OK):

{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "COMPLETED",
  "verdict": "SAFE",
  "score": 0.87,
  "composite_score": 0.85,
  "progress_score": 0.92,
  "safety_score": 0.78,
  "consistency": 0.90,
  "success_rate": 1.0,
  "vlm_agreement": true,
  "needs_review": false,
  "episode_details": [...]
}

Arena Submissions

Create Submission

Submit a policy to the arena for ranking.

POST /submissions

Content-Type: multipart/form-data

Parameters:

Name Type Required Description
policy file Yes Zip file containing policy.py
scenario_id string Yes Target scenario ID

Example:

curl -X POST https://api.botmanifold.com/submissions \
  -H "Authorization: Bearer $BOTMANIFOLD_API_KEY" \
  -F "policy=@policy.zip" \
  -F "scenario_id=messy_room"
from botmanifold import BotManifoldClient

client = BotManifoldClient(api_key="bm_...")
submission = client.arena.submit("policy.zip", scenario="messy_room")

Response (201 Created):

{
  "submission_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "QUEUED",
  "scenario_id": "messy_room",
  "created_at": "2026-01-20T10:30:00Z"
}

List Submissions

GET /submissions

Query Parameters:

Name Type Default Description
scenario string - Filter by scenario ID
limit integer 20 Max results (1-100)
offset integer 0 Pagination offset

Example:

curl -H "Authorization: Bearer $BOTMANIFOLD_API_KEY" \
  "https://api.botmanifold.com/submissions?scenario=messy_room&limit=10"

Response (200 OK):

{
  "submissions": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "scenario_id": "messy_room",
      "status": "COMPLETED",
      "verdict": "SAFE",
      "score": 95.5,
      "created_at": "2026-01-20T10:30:00Z"
    }
  ],
  "total": 42,
  "limit": 10,
  "offset": 0
}

Get Submission

GET /submissions/{id}

Response (200 OK):

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "scenario_id": "messy_room",
  "status": "COMPLETED",
  "verdict": "SAFE",
  "score": 95.5,
  "video_url": "https://storage.botmanifold.com/videos/550e8400.mp4",
  "confidence": 0.92,
  "error_message": null,
  "created_at": "2026-01-20T10:30:00Z",
  "completed_at": "2026-01-20T10:32:15Z"
}

Submission Events (SSE)

Stream real-time updates for a submission.

GET /submissions/{id}/events

Content-Type: text/event-stream

Example:

const eventSource = new EventSource(
  'https://api.botmanifold.com/submissions/550e8400.../events'
);

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Status:', data.status);

  if (data.done) {
    eventSource.close();
  }
};

Scenarios

List Scenarios

GET /scenarios

Example:

curl -H "Authorization: Bearer $BOTMANIFOLD_API_KEY" \
  "https://api.botmanifold.com/scenarios"

Response (200 OK):

{
  "scenarios": [
    {
      "id": "messy_room",
      "name": "Messy Room Challenge",
      "description": "Clean up scattered items in a room",
      "difficulty": 2,
      "time_limit": 60,
      "max_score": 120
    }
  ]
}

Get Scenario

GET /scenarios/{id}

Response (200 OK):

{
  "id": "messy_room",
  "name": "Messy Room Challenge",
  "description": "Clean up scattered items in a room",
  "difficulty": 2,
  "time_limit": 60,
  "max_score": 120,
  "long_description": "The Messy Room scenario challenges..."
}

Error Responses

Validation Error (400)

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid scenario ID: unknown_scenario",
    "details": {
      "field": "scenario_id",
      "value": "unknown_scenario"
    }
  }
}

Unauthorized (401)

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Missing or invalid API key"
  }
}

Not Found (404)

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Submission not found"
  }
}

Rate Limited (429)

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests. Try again in 60 seconds.",
    "retry_after": 60
  }
}