Reference
Complete technical specification for Runhuman. Integration guides link here for shared details.
Job Lifecycle
Every test follows this sequence:
| Status | Description | Terminal |
|---|---|---|
| pending | Job created, queued for posting to testers | No |
| waiting | Posted to Slack, awaiting tester claim | No |
| working | Tester claimed and is actively testing | No |
| completed | Test finished, results extracted | Yes |
| incomplete | Test finished but missing required data | Yes |
| abandoned | Tester abandoned before completing | Yes |
| rejected | Tester determined instructions were invalid or impossible | Yes |
| error | System error occurred | Yes |
Terminal statuses will not change. Non-terminal statuses should be polled until resolution.
Output Schema
Define the structure of data you want extracted from the tester’s response.
Format
{
[fieldName: string]: {
type: "boolean" | "string" | "number" | "array" | "object";
description: string;
example?: any;
}
}
Example
{
"loginWorks": {
"type": "boolean",
"description": "Does login work with valid credentials?"
},
"errorMessage": {
"type": "string",
"description": "What error appears for invalid password?"
},
"issuesFound": {
"type": "array",
"description": "List of any UI/UX issues discovered"
}
}
Keep schemas simple. Testers describe findings in natural language, and GPT-4o extracts structured data matching your schema.
Cost
Tests are billed per second at $0.0018/second.
| Duration | Cost |
|---|---|
| 60 seconds | $0.108 |
| 120 seconds | $0.216 |
| 300 seconds (5 min) | $0.54 |
| 600 seconds (10 min) | $1.08 |
Duration is rounded up using Math.ceil(). A test lasting 61 seconds costs the same as 62 seconds. Cost is stored at full precision, not rounded to cents.
Request Parameters
These parameters apply to all job creation endpoints.
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | URL for the tester to visit |
| description | string | Yes | Instructions for the tester |
| outputSchema | object | No | Schema defining data to extract. If omitted, only success/explanation returned |
| targetDurationMinutes | number | No | Time limit in minutes. Default: 5. Range: 1-60 |
| allowDurationExtension | boolean | No | Allow tester to request more time. Default: true |
| maxExtensionMinutes | number or false | No | Maximum extension allowed. Default: false (unlimited) |
| additionalValidationInstructions | string | No | Custom instructions for AI result validation |
| screenSize | string or object | No | Screen size: “desktop”, “laptop”, “tablet”, “mobile”, or custom dimensions |
| repoName | string | No | GitHub repo (“owner/repo”) for context. Fetches README.md and CLAUDE.md |
| canCreateGithubIssues | boolean | No | Auto-create GitHub issues from bugs. Requires repoName. Default: false |
additionalValidationInstructions
Use this parameter to guide how GPT-4o interprets results:
{
"additionalValidationInstructions": "Ignore minor UI glitches in the header. Focus only on whether the order was placed and confirmation number displayed."
}
screenSize
Control the browser viewport for testing different devices:
| Preset | Dimensions |
|---|---|
| desktop | 1920x1080 |
| laptop | 1366x768 |
| tablet | 768x1024 |
| mobile | 375x667 |
Or specify custom dimensions:
{
"screenSize": { "width": 1440, "height": 900 }
}
Response Fields
Completed jobs return these fields:
| Field | Type | Description |
|---|---|---|
| status | string | Job status (see Job Lifecycle) |
| result | object | Extracted data matching your outputSchema |
| result.success | boolean | Whether extraction succeeded |
| result.explanation | string | GPT-4o’s interpretation of the test |
| result.data | object | Structured data matching your schema |
| costUsd | number | Total cost in USD |
| testDurationSeconds | number | Time the tester spent |
| testerResponse | string | Raw natural language feedback before extraction |
| testerAlias | string | Anonymized tester name (e.g., “Tester Alpha”) |
| testerAvatarUrl | string | Avatar image URL for UI display |
| testerColor | string | Hex color for tester identity (e.g., “#4A90E2”) |
| testerData | object | Captured testing artifacts |
Tester Data
The testerData object contains artifacts captured during the test session:
{
testDurationSeconds: number;
consoleMessages: Array<{
type: string; // "log", "error", "warn", etc.
message: string;
timestamp: string;
}>;
networkRequests: Array<{
url: string;
method: string; // "GET", "POST", etc.
status?: number; // HTTP status code
timestamp: string;
}>;
clicks: Array<{
x: number;
y: number;
timestamp: string;
element?: string; // Element selector if available
}>;
screenshots: string[]; // URLs to captured screenshots
videoUrl?: string; // URL to session recording
}
API Endpoints
POST /api/run
Synchronous endpoint. Creates a job and waits for completion, blocking up to 10 minutes.
Request:
{
"url": "https://example.com",
"description": "Test the checkout flow",
"outputSchema": {
"checkoutWorks": { "type": "boolean", "description": "Order placed successfully?" }
}
}
Response (200):
{
"status": "completed",
"result": {
"success": true,
"explanation": "Checkout completed successfully",
"data": { "checkoutWorks": true }
},
"costUsd": 0.396,
"testDurationSeconds": 220,
"testerResponse": "I completed the checkout...",
"testerAlias": "Tester Alpha",
"testerData": { ... }
}
Response (408): Test did not complete within 10 minutes.
POST /api/jobs
Asynchronous endpoint. Creates a job and returns immediately.
Response (201):
{
"jobId": "job_abc123",
"message": "Job created successfully. Use GET /api/job/:id to check status."
}
GET /api/job/:jobId
Retrieves job status and results.
Response:
{
"id": "job_abc123",
"status": "completed",
"result": { ... },
"costUsd": 0.54,
"testDurationSeconds": 300,
"testerResponse": "...",
"testerData": { ... }
}
Fields like result, costUsd, and testerResponse only appear when status is completed.
MCP Tools
create_job
Creates a QA job and returns immediately.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | URL to test |
| description | string | Yes | Instructions for tester |
| outputSchema | object | No | JSON Schema for result extraction |
| targetDurationMinutes | number | No | Time limit. Default: 5 |
| allowDurationExtension | boolean | No | Allow extra time. Default: true |
| maxExtensionMinutes | number or false | No | Max extension. Default: false |
| additionalValidationInstructions | string | No | Custom AI validation instructions |
| screenSize | string or object | No | Browser viewport size |
| repoName | string | No | GitHub repo for context |
| canCreateGithubIssues | boolean | No | Auto-create issues from bugs |
Returns: Job ID and status message.
wait_for_result
Polls job status and returns results when complete.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| jobId | string | Yes | Job ID from create_job |
| waitSeconds | number | No | How long to wait. Default: 30. Range: 1-300 |
Behavior:
- Checks status before waiting (returns immediately if already complete)
- Polls every 5 seconds during the wait period
- Returns results when job completes or suggests retrying with longer wait
Recommended pattern: Start with 30 seconds, then 45, then 60, increasing on each retry.
Error Codes
| HTTP Status | Meaning |
|---|---|
| 400 | Bad request. Invalid parameters. |
| 401 | Unauthorized. Invalid or missing API key. |
| 404 | Not found. Job does not exist. |
| 408 | Timeout. Synchronous request exceeded 10 minutes. |
| 500 | Server error. |
All errors return this format:
{
"error": "Error type",
"message": "Detailed description"
}
Authentication
Include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Get your key from the API Keys dashboard.