This guide walks you through creating your first HumanRail task — from getting an API key to receiving a verified human judgment. Works with Python, TypeScript, and Go.
Sign up at humanrail.dev or log in to the customer dashboard. Navigate to Settings → API Keys and generate a new key.
API keys are prefixed with ek_live_ for production and ek_test_ for
sandbox. Use the sandbox key during development — it simulates worker responses
without hitting the real worker pool.
Set the key as an environment variable:
export HUMANRAIL_API_KEY="ek_test_your_key_here"
Choose your language and install the HumanRail client library.
pip install humanrail
npm install @humanrail/sdk
go get github.com/prime001/humanrail-sdk/go
A task is a unit of work routed to a vetted human worker. You define the input payload, the expected output schema, and a payout amount. HumanRail handles routing, verification, and payment.
from humanrail import HumanRail
client = HumanRail(api_key="ek_live_...")
task = client.tasks.create(
type="content_review",
payload={
"text": "Is this review genuine?",
"content": "Great product, 5 stars!",
},
output_schema={
"type": "object",
"required": ["verdict"],
"properties": {
"verdict": {
"type": "string",
"enum": ["genuine", "ai_generated", "uncertain"],
},
"notes": {"type": "string"},
},
},
payout_sats=500,
sla_seconds=300,
skills_required=["content_review"],
)
print(f"Task created: {task.id}")
# Task created: 01abc123-...
import { HumanRail } from '@humanrail/sdk';
const client = new HumanRail({ apiKey: 'ek_live_...' });
const task = await client.tasks.create({
type: 'content_review',
payload: {
text: 'Is this review genuine?',
content: 'Great product, 5 stars!',
},
outputSchema: {
type: 'object',
required: ['verdict'],
properties: {
verdict: {
type: 'string',
enum: ['genuine', 'ai_generated', 'uncertain'],
},
notes: { type: 'string' },
},
},
payoutSats: 500,
slaSeconds: 300,
skillsRequired: ['content_review'],
});
console.log(`Task created: ${task.id}`);
// Task created: 01abc123-...
package main
import (
"context"
"fmt"
humanrail "github.com/prime001/humanrail-sdk/go"
)
func main() {
client := humanrail.NewClient("ek_live_...")
task, err := client.Tasks.Create(context.Background(), &humanrail.CreateTaskRequest{
Type: "content_review",
Payload: map[string]any{
"text": "Is this review genuine?",
"content": "Great product, 5 stars!",
},
PayoutSats: 500,
SLASeconds: 300,
SkillsRequired: []string{"content_review"},
})
if err != nil {
panic(err)
}
fmt.Println("Task created:", task.ID)
}
When you call tasks.create(), HumanRail assigns the task to a qualified
worker within seconds. The worker completes the task, their response passes through
our 6-stage verification pipeline, and you receive the verified result.
There are two ways to receive the verified result: webhooks (recommended for production) or polling (simpler for development).
Register a webhook endpoint to receive real-time notifications. HumanRail will
POST a task.verified event when the worker's response passes verification.
See the Webhooks guide for full details.
from fastapi import FastAPI, Request, HTTPException
from humanrail import verify_webhook_signature
import os
app = FastAPI()
@app.post("/webhooks/humanrail")
async def handle_webhook(request: Request):
body = await request.body()
signature = request.headers.get("x-humanrail-signature")
if not verify_webhook_signature(
payload=body,
signature=signature,
secret=os.environ["HUMANRAIL_WEBHOOK_SECRET"],
):
raise HTTPException(status_code=401)
event = await request.json()
if event["type"] == "task.verified":
print("Result:", event["data"]["output"])
# {"verdict": "genuine", "notes": "Appears authentic"}
return {"ok": True}
import express from 'express';
import { verifyWebhookSignature } from '@humanrail/sdk';
const app = express();
app.post('/webhooks/humanrail',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-humanrail-signature'];
const isValid = verifyWebhookSignature({
payload: req.body,
signature,
secret: process.env.HUMANRAIL_WEBHOOK_SECRET,
});
if (!isValid) return res.status(401).send('Invalid signature');
const event = JSON.parse(req.body);
if (event.type === 'task.verified') {
console.log('Result:', event.data.output);
// { verdict: "genuine", notes: "Appears authentic" }
}
res.sendStatus(200);
}
);
func webhookHandler(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
signature := r.Header.Get("X-Humanrail-Signature")
if !humanrail.VerifyWebhookSignature(body, signature, webhookSecret) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
var event humanrail.WebhookEvent
json.Unmarshal(body, &event)
if event.Type == "task.verified" {
fmt.Println("Result:", event.Data.Output)
}
w.WriteHeader(http.StatusOK)
}
For development or simple scripts, you can poll the task status until it reaches a terminal state.
import time
while True:
task = client.tasks.get(task.id)
if task.status == "verified":
print("Result:", task.output)
break
elif task.status in ("failed", "expired", "cancelled"):
print(f"Task ended: {task.status}")
break
time.sleep(5) # poll every 5 seconds
const waitForResult = async (taskId: string) => {
while (true) {
const task = await client.tasks.get(taskId);
if (task.status === 'verified') return task.output;
if (['failed', 'expired', 'cancelled'].includes(task.status)) {
throw new Error(`Task ended: ${task.status}`);
}
await new Promise(r => setTimeout(r, 5000));
}
};
const output = await waitForResult(task.id);
console.log(output);
// { verdict: "genuine", notes: "Appears authentic" }
// Use the built-in helper that polls for you
result, err := client.Tasks.WaitForCompletion(
context.Background(), task.ID, nil,
)
if err != nil {
panic(err)
}
fmt.Println("Result:", result.Output)
Webhooks are strongly recommended for production. Polling works for development
and simple scripts, but adds latency and wastes resources. Use the
task.verified webhook event for real-time results.
HumanRail supports any task type you define. Here are some common ones to get you started:
| Task Type | Description | Typical SLA | Typical Payout |
|---|---|---|---|
content_review |
Determine if user-generated content is genuine, AI-generated, or policy-violating | 5 min | 200-500 sats |
refund_eligibility |
Evaluate whether a refund request meets your return policy criteria | 5 min | 300-800 sats |
document_verification |
Verify that an uploaded document (ID, proof of address) is valid and matches claims | 15 min | 500-2000 sats |
sentiment_analysis |
Classify the sentiment and intent of customer messages when AI confidence is low | 3 min | 100-300 sats |
image_moderation |
Classify images as safe, NSFW, violent, or policy-violating | 5 min | 200-500 sats |
translation_review |
Verify machine translation accuracy and cultural appropriateness | 10 min | 500-1500 sats |
You can create any task type with any output schema. Define the
outputSchema as a JSON Schema object and HumanRail will
auto-generate the worker form and validate submissions against it.