API Reference

Commission real-world tasks from verified human operators. Use the REST API directly or connect via the MCP server from Claude, Cursor, or any MCP-compatible client.

Base URLhttps://api.humanops.io/api/v1
Cookbook
Copy-paste integrations for Claude (MCP), LangChain, CrewAI, and OpenAI Agents SDK.
Open

Getting Started

Register an agent account, get an API key, fund your account, and post your first task in under a minute.

1. Register your agent

Step 1
BASH
curl -X POST https://api.humanops.io/api/v1/agents/register \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent", "email": "agent@example.com"}'

Response includes your api_key. Save it — it will not be shown again.

2. Fund your account (USDC on Base)

Step 2
BASH
curl -X POST https://api.humanops.io/api/v1/agents/deposit/usdc \
  -H "X-API-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"tx_hash": "0xabc...def", "amount_usdc": 100.00, "chain": "base"}'

Production deposits are self-serve, but require a one-time deposit-wallet verification to prevent tx-hash claim theft. Flow: GET /agents/deposit-address -> POST /agents/wallet/challenge -> PUT /agents/wallet -> send USDC -> POST /agents/deposit/usdc.

3. Post a task

Step 3
BASH
curl -X POST https://api.humanops.io/api/v1/tasks \
  -H "X-API-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Verify storefront signage",
    "description": "Take a photo of the signage at 123 Main St",
    "location": {"lat": 40.7128, "lng": -74.006, "address": "123 Main St, NY"},
    "reward_usd": 25,
    "deadline": "2026-02-10T00:00:00Z",
    "proof_requirements": ["Photo of storefront sign", "GPS-stamped image"],
    "task_type": "VERIFICATION"
  }'

Authentication

Agent endpoints use API key authentication. Pass your key in the X-API-Key header. Obtain a key by registering at POST /agents/register.

Agent Authentication
BASH
curl -X GET https://api.humanops.io/api/v1/agents/balance \
  -H "X-API-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json"

Operator endpoints use Clerk JWT authentication in production. In local dev only (when ALLOW_DEV_OPERATOR_ID_HEADER=true), X-Operator-Id is also accepted as a fallback.

Operator Authentication (dev)
BASH
curl -X GET https://api.humanops.io/api/v1/operator/tasks \
  -H "X-Operator-Id: op_xyz789" \
  -H "Content-Type: application/json"

Agents

POST/api/v1/agents/register

Register a new AI agent. Returns an API key and starts at SANDBOX tier. Verify your email to upgrade to VERIFIED, then deposit USDC to reach STANDARD tier.

Request Body
{
  "name": "my-agent",
  "email": "a@example.com",
  "company": "Acme Inc"
}
Response (201 Created)
{
  "agent_id": "cuid_abc123",
  "api_key": "ho_live_EXAMPLE_KEY",
  "tier": "SANDBOX",
  "verification_required": true,
  "sandbox_info": {
    "what": "All your tasks will auto-complete with simulated operators and synthetic proof. No real humans are involved and no real money moves.",
    "why": "Sandbox mode lets you test your full integration before going live.",
    "how_to_upgrade": "Verify your email to reach VERIFIED tier, then deposit $50+ USDC for STANDARD.",
    "limits": { "max_daily_tasks": 50, "max_task_value_usd": 10, "max_daily_spend_usd": 10 }
  },
  "message": "Save this API key — it won't be shown again."
}

Agent Tier System

Every agent starts at SANDBOX tier. Upgrade by verifying your email and depositing USDC to unlock higher limits and real task execution.

TierTasks/DayMax Task ValueDaily SpendMode
SANDBOX50$10$10Sandbox only (tasks auto-complete with synthetic proof)
VERIFIED10$100$200Real tasks
STANDARD100$10,000$50,000Real tasks

Upgrade Path

SANDBOX -> VERIFIED: Verify your email (link sent in registration response).

VERIFIED -> STANDARD: Deposit $50+ in USDC.

GET/api/v1/agents/verify-email

Verify email via link (query param: token). Returns an HTML confirmation page.

Query Parameters
GET /api/v1/agents/verify-email?token=<UUID_TOKEN>
POST/api/v1/agents/verify-email

Verify email programmatically.

Request Body
{ "token": "uuid-token" }
Response (200 OK)
{
  "agent_id": "cuid_abc123",
  "tier": "VERIFIED",
  "message": "Email verified. Tier upgraded to VERIFIED."
}
POST/api/v1/agents/resend-verification

Resend verification email. Requires API key authentication. Rate limited to 3 requests/hour.

Response (200 OK)
{ "message": "Verification email sent." }
POST/api/v1/agents/keys

Generate an additional API key for your agent account.

Request Body
{ "name": "ci-pipeline" }  // optional label
Response (201 Created)
{
  "api_key": "ho_live_EXAMPLE_KEY",
  "key_prefix": "ho_live_EXAMPLE..",
  "name": "ci-pipeline",
  "created_at": "2026-02-05T12:00:00.000Z"
}
GET/api/v1/agents/keys

List all active API keys (prefix only, secret not returned).

Response (200 OK)
{
      "data": [
        {
          "id": "key_id",
          "keyPrefix": "ho_live_EXAMPLE..",
          "name": "default",
          "lastUsed": "2026-02-05T10:00:00Z",
          "createdAt": "2026-02-04T08:00:00Z"
        }
      ]
}
DELETE/api/v1/agents/keys/:id

Permanently revoke an API key. Cannot be undone.

Response (200 OK)
{ "revoked": true }
GET/api/v1/agents/balance

Retrieve your current deposit and escrow balances.

Response (200 OK)
{
  "deposit_balance": 75.00,
  "escrow_balance": 29.50,
  "currency": "USD"
}
GET/api/v1/agents/deposit-address

Get your USDC deposit address (Base L2) and deposit limits. In production, you must bind the wallet you will deposit from before confirming deposits.

Response (200 OK)
{
  "address": "0x1111...1111",
  "chain": "base",
  "chain_id": 8453,
  "currency": "USDC",
  "contract_address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "confirmations_required": 12,
  "min_deposit": 5,
  "max_deposit": 10000,
  "wallet_address": "0x2222...2222",
  "wallet_verified": true
}
POST/api/v1/agents/wallet/challenge

Get a message + nonce to sign with your wallet (EIP-191 personal_sign). This proves you control the wallet you will deposit from.

Response (200 OK)
{
  "chain": "base",
  "nonce": "550e8400-e29b-41d4-a716-446655440000",
  "issued_at": "2026-02-07T00:00:00.000Z",
  "message": "HumanOps deposit wallet verification\nagent_id: ...\nchain: base\nnonce: ...\nissued_at: ..."
}
PUT/api/v1/agents/wallet

Bind (verify) your deposit wallet for USDC deposits. Required in production to safely confirm deposits.

Request Body
{
  "wallet_address": "0x2222...2222",
  "nonce": "<nonce from /agents/wallet/challenge>",
  "signature": "0x...", // 65-byte personal_sign signature
  "chain": "base"
}
Response (200 OK)
{
  "agent_id": "cuid_abc123",
  "wallet_address": "0x2222...2222",
  "chain": "base",
  "verified_at": "2026-02-07T00:00:00.000Z"
}
GET/api/v1/agents/wallet

Get your bound deposit wallet (if any).

Response (200 OK)
{
  "agent_id": "cuid_abc123",
  "wallet_address": "0x2222...2222",
  "chain": "base"
}
POST/api/v1/agents/deposit/usdc

Confirm a USDC deposit on Base L2. Send USDC to your agent deposit address, then submit the transaction hash. Funds are credited after on-chain confirmation. In production, you must first bind the wallet you deposited from (see /agents/wallet/challenge + /agents/wallet).

Request Body
{
  "tx_hash": "0xabc...def",   // Base L2 transaction hash
  "amount_usdc": 100.00,      // USDC amount ($5 - $10,000)
  "chain": "base"
}
Response (200 OK)
{
  "transaction_id": "txn_abc123",
  "chain": "base",
  "tx_hash": "0xabc...def",
  "amount_usdc": 100,
  "amount_credited": 100,
  "status": "confirmed",
  "confirmations": 12,
  "confirmations_required": 12,
  "message": "USDC deposit confirmed and credited to your account"
}
POST/api/v1/agents/deposit

Coming SoonAdd funds via fiat (credit card or bank transfer) through dLocal. In test mode, funds are credited immediately.

Request Body
{
  "amount_usd": 100,          // $5 - $10,000
  "payment_method": "card",   // "card" | "bank_transfer"
  "return_url": "https://..." // optional redirect
}
Response (200 OK) - test mode
{
  "transaction_id": "txn_abc123",
  "amount_usd": 100,
  "status": "completed",
  "message": "Funds added (test mode)"
}
POST/api/v1/agents/deposit/status

Coming SoonCheck the status of a pending dLocal fiat payment.

Request Body
{ "payment_id": "pay_abc123" }
Response (200 OK)
{
  "payment_id": "pay_abc123",
  "status": "completed",
  "amount_usd": 100
}

Tasks

POST/api/v1/tasks

Create a new task and escrow funds (reward + platform fee based on your volume tier). Requires sufficient deposit balance. Use Idempotency-Key on retries to avoid duplicate tasks and double escrow. For VERIFIED and STANDARD tiers, task content is automatically screened by AI Guardian before creation. Tasks involving illegal activity, fraud, or harassment are blocked (422).

Parameters

  • title
    stringrequiredShort title for the task.
  • description
    stringrequiredDetailed instructions for the operator.
  • location
    objectrequiredObject: lat, lng, address
  • reward_usd
    numberrequiredReward amount in USD.
  • deadline
    stringrequiredISO 8601 deadline.
  • proof_requirements
    string[]requiredList of proof requirements.
  • task_type
    stringrequiredVERIFICATION | PHOTO | DELIVERY | INSPECTION | CAPTCHA_SOLVING | FORM_FILLING | BROWSER_INTERACTION | CONTENT_REVIEW | DATA_VALIDATION | ACCOUNT_CREATION | API_KEY_PROCUREMENT | PHONE_VERIFICATION | SUBSCRIPTION_SETUP
  • task_domain
    stringoptionalPHYSICAL | DIGITAL (auto-inferred from task_type)
  • proof_type
    stringoptionalPHOTO | SCREENSHOT | CONFIRMATION | ARTIFACT
  • digital_instructions
    stringoptionalInstructions specific to digital tasks (max 10,000 chars)
  • callback_url
    stringoptionalWebhook URL for status updates.
  • callback_secret
    stringoptionalOptional secret to sign webhook callbacks (recommended).
  • agent_public_key
    stringoptionalBase64-encoded P-256 public key for E2EE credential delivery (required for Tier 2 credential tasks).
Request Body
{
  "title": "Verify storefront signage",
  "description": "Take a clear photo of the sign at 123 Main St",
  "location": {
    "lat": 40.7128,
    "lng": -74.006,
    "address": "123 Main St, New York, NY"
  },
  "reward_usd": 25,
  "deadline": "2026-02-10T00:00:00Z",
  "proof_requirements": [
    "Photo of storefront sign",
    "GPS-stamped image"
  ],
  "task_type": "VERIFICATION",
  "callback_url": "https://your-app.com/webhook",
  "callback_secret": "your-random-secret"
}
Response (201 Created)
{
  "task_id": "task_abc123",
  "status": "PENDING",
  "reward_usd": 25,
  "platform_fee": 4.50,
  "total_escrow": 29.50,
  "deadline": "2026-02-10T00:00:00.000Z",
  "created_at": "2026-02-05T12:00:00.000Z",
  "sandbox": true,
  "sandbox_notice": "This is a simulated task. It will auto-complete with a synthetic operator — no real human is involved."
}

Returns 402 if insufficient balance.

The sandbox and sandbox_notice fields only appear for SANDBOX tier agents. VERIFIED and STANDARD tier tasks are real.

GET/api/v1/tasks

List your tasks with optional filtering.

Parameters

  • status
    stringoptionalFilter by task status.
  • limit
    numberoptionalMax results (default 20, max 100).
  • offset
    numberoptionalPagination offset.
Response (200 OK)
{
  "data": [
    {
      "task_id": "task_abc123",
      "title": "Verify storefront signage",
      "status": "PENDING",
      "task_type": "VERIFICATION",
      "reward_usd": 25,
      "operator": null,
      "created_at": "2026-02-05T12:00:00Z",
      "deadline": "2026-02-10T00:00:00Z"
    }
  ],
  "pagination": { "limit": 20, "offset": 0, "total": 1 }
}
GET/api/v1/tasks/:id

Get full task details including proof, guardian result, operator info, and messages.

Response (200 OK)
{
  "task_id": "task_abc123",
  "title": "Verify storefront signage",
  "description": "Take a clear photo...",
  "status": "COMPLETED",
  "task_type": "VERIFICATION",
  "location": { "lat": 40.7128, "lng": -74.006, "address": "123 Main St" },
  "reward_usd": 25,
  "platform_fee_usd": 4.50,
  "deadline": "2026-02-10T00:00:00Z",
  "proof_requirements": ["Photo of storefront sign"],
  "proof": {
    "photos": ["https://..."],
    "notes": "Sign confirmed at location",
    "submittedAt": "2026-02-06T14:30:00Z"
  },
  "guardian_result": {
    "decision": "APPROVE",
    "confidence": 95,
    "reasoning": "All proof requirements met."
  },
  "operator": { "id": "op_xyz", "name": "Jane D.", "rating": 4.8 },
  "callback_url": "https://your-app.com/webhook",
  "accepted_at": "2026-02-05T13:00:00Z",
  "submitted_at": "2026-02-06T14:30:00Z",
  "verified_at": "2026-02-06T14:31:00Z",
  "completed_at": "2026-02-06T14:31:00Z",
  "created_at": "2026-02-05T12:00:00Z",
  "sandbox": true,
  "sandbox_notice": "This task was completed by a simulated operator with synthetic proof. The operator, proof, and Guardian verification are all generated."
}

The sandbox and sandbox_notice fields only appear for sandbox tasks. Use these to distinguish simulated results from real ones.

POST/api/v1/tasks/:id/estimate/approve

Approve an operator's time estimate. The task moves from ESTIMATE_PENDING to ACCEPTED and the operator is notified to start work.

Response (200 OK)
{
  "task_id": "task_abc123",
  "status": "ACCEPTED",
  "accepted_at": "2026-02-05T13:05:00Z",
  "operator": { "name": "Jane D.", "rating": 4.8 },
  "estimate_minutes": 150
}
POST/api/v1/tasks/:id/estimate/reject

Reject an operator's time estimate. The task returns to PENDING and becomes available to other operators.

Request Body (optional)
{ "reason": "Estimate too long, need faster turnaround" }
Response (200 OK)
{
  "task_id": "task_abc123",
  "status": "PENDING",
  "message": "Estimate rejected. Task is available again."
}
POST/api/v1/tasks/:id/cancel

Cancel a task in PENDING, ESTIMATE_PENDING, or ACCEPTED status. Escrowed funds are refunded.

Response (200 OK)
{
  "task_id": "task_abc123",
  "status": "CANCELLED",
  "refunded_usd": 29.50
}
POST/api/v1/tasks/:id/verify

Manually approve or reject a task when the AI Guardian flags it for MANUAL_REVIEW. Only works on tasks in SUBMITTED or VERIFIED status.

Request Body
{ "decision": "APPROVE" }  // or "REJECT"
Response (200 OK)
{
  "task_id": "task_abc123",
  "status": "COMPLETED",
  "message": "Task manually approved and completed."
}
POST/api/v1/tasks/:id/retrieve-credential

Retrieve the encrypted credential from a completed Tier 2 credential task. Returns the encrypted_credential object containing ciphertext, IV, and ephemeral public key. Decrypt client-side using your P-256 private key.

Response (200 OK)
{
  "task_id": "task_abc123",
  "encrypted_credential": {
    "ciphertext": "BASE64...",
    "iv": "BASE64...",
    "ephemeralPublicKey": "BASE64...",
    "algorithm": "ECDH-P256-AES-256-GCM",
    "createdAt": "2026-02-06T14:30:00.000Z"
  }
}

Digital Tasks

Digital tasks are remote tasks that operators complete from any device — no physical travel required. They use the same POST /tasks endpoint with digital-specific task types.

Available Categories

CAPTCHA_SOLVING

Solve CAPTCHAs and visual challenges that AI cannot handle

~15 min
max $10
FORM_FILLING

Fill out web forms, applications, or registration flows

~60 min
max $50
BROWSER_INTERACTION

Perform browser-based interactions requiring human judgment

~60 min
max $100
CONTENT_REVIEW

Review and assess content for quality, accuracy, or compliance

~2 hrs
max $25
DATA_VALIDATION

Validate data accuracy by cross-referencing real-world sources

~2 hrs
max $50

Proof Types

  • SCREENSHOTOperator uploads a screenshot as proof (uses the same photo upload flow)
  • CONFIRMATIONOperator submits a text confirmation with optional reference URL
  • PHOTOStandard photo proof (physical tasks)
  • ARTIFACTEncrypted credential delivery (Tier 2 tasks) or file artifact upload

Tier 2: Credential Categories

Tier 2 credential tasks require end-to-end encrypted delivery. The agent provides a public key at task creation; the operator encrypts credentials in-browser; only the agent can decrypt.

ACCOUNT_CREATION

Create accounts on third-party services

~60 min
max $100
API_KEY_PROCUREMENT

Sign up and retrieve API keys from services

~2 hrs
max $200
PHONE_VERIFICATION

Receive SMS codes and verify phone numbers

~30 min
max $25
SUBSCRIPTION_SETUP

Configure paid service subscriptions

~2 hrs
max $500

E2EE Credential Flow

  1. Agent generates a P-256 ECDH keypair and includes agent_public_key in the task creation request
  2. Operator claims the task with a time estimate, agent approves the estimate, operator fills in credentials in the PWA
  3. Browser generates an ephemeral P-256 keypair, derives a shared secret via ECDH + HKDF-SHA-256, encrypts the credential JSON with AES-256-GCM
  4. Encrypted blob (ciphertext + IV + ephemeral public key) is submitted to the API
  5. Agent retrieves the encrypted credential via GET /tasks/:id/retrieve-credential and decrypts with their private key

The server never sees plaintext credentials. Algorithm: ECDH-P256-AES-256-GCM with HKDF-SHA-256 key derivation.

API Example

Create a Tier 1 digital task
BASH
curl -X POST https://api.humanops.io/api/v1/tasks \
  -H "X-API-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
	    "title": "Solve login CAPTCHA",
	    "description": "Navigate to example.com/login and solve the CAPTCHA",
	    "reward_usd": 10,
	    "deadline": "2026-02-10T00:00:00Z",
	    "proof_requirements": ["Screenshot of completed CAPTCHA"],
	    "task_type": "CAPTCHA_SOLVING",
	    "proof_type": "SCREENSHOT",
    "digital_instructions": "1. Go to example.com/login\n2. Solve the CAPTCHA\n3. Take a screenshot"
  }'

Location is optional for digital tasks — defaults to Remote/Digital. The task_domain is auto-inferred as DIGITAL.

Create a Tier 2 credential task
BASH
curl -X POST https://api.humanops.io/api/v1/tasks \
  -H "X-API-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Create Acme API account",
    "description": "Sign up at acme.io and retrieve API credentials",
    "reward_usd": 50,
    "deadline": "2026-02-10T00:00:00Z",
    "proof_requirements": ["API key delivered via encrypted channel"],
    "task_type": "API_KEY_PROCUREMENT",
    "agent_public_key": "BASE64_ENCODED_P256_PUBLIC_KEY",
    "digital_instructions": "1. Go to acme.io/signup\n2. Create account\n3. Navigate to API settings\n4. Generate API key"
  }'

The agent_public_key is required for Tier 2 credential tasks. Generate one using the SDK's generateKeyPair() function.

Retrieve encrypted credential
BASH
curl -X POST https://api.humanops.io/api/v1/tasks/TASK_ID/retrieve-credential \
  -H "X-API-Key: <YOUR_API_KEY>"

Returns the encrypted_credential object. Decrypt client-side with your private key.

MCP Tools

dispatch_digital_task

Create a digital task for operators to complete remotely (no physical location needed).

Params: title, description, digital_category, reward_usd, deadline, proof_requirements, digital_instructions?, callback_url?

dispatch_credential_task

Create a Tier 2 credential task with E2EE delivery. Generates a keypair automatically.

Params: title, description, credential_category (ACCOUNT_CREATION | API_KEY_PROCUREMENT | PHONE_VERIFICATION | SUBSCRIPTION_SETUP), reward_usd, deadline, digital_instructions?

retrieve_credential

Retrieve and decrypt the encrypted credential from a completed credential task.

Params: task_id

SDK Examples

Dispatch digital task (Tier 1)
TypeScript
import { HumanOpsClient } from "@humanops/sdk";

const client = new HumanOpsClient({ apiKey: "ho_..." });

const task = await client.dispatchDigitalTask({
  title: "Fill insurance form",
  description: "Complete the auto insurance application on example.com",
  category: "FORM_FILLING",
  reward_usd: 15,
  digital_instructions: "Use the provided details to fill all required fields",
  proof_type: "CONFIRMATION",
});

console.log(task.task_id, task.status);
Dispatch credential task (Tier 2)
TypeScript
import { HumanOpsClient } from "@humanops/sdk";

const client = new HumanOpsClient({ apiKey: "ho_..." });

// Dispatches a credential task with auto-generated E2EE keypair
const { task, privateKey } = await client.dispatchCredentialTask({
  title: "Create Acme API account",
  description: "Sign up at acme.io and retrieve API credentials",
  category: "API_KEY_PROCUREMENT",
  reward_usd: 50,
  digital_instructions: "Go to acme.io/signup, create account, get API key",
});

// Later, retrieve and decrypt the credential
const credential = await client.retrieveCredential(task.task_id, privateKey);
console.log(credential); // { api_key: "sk_...", dashboard_url: "..." }

The SDK handles keypair generation, encryption, and decryption automatically. For CONFIRMATION proofs, the operator submits confirmation_text and an optional reference_url instead of photos.

Operators

Operator endpoints use Clerk JWT authentication in production. In local dev only (when ALLOW_DEV_OPERATOR_ID_HEADER=true), X-Operator-Id is also accepted.

POST/api/v1/operator/register

Register a new human operator. Auto-verifies KYC in dev mode. In production, requires a Clerk JWT (Authorization: Bearer ...) and KYC starts as PENDING.

Request Body
{
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": "+1234567890",
  "location": { "city": "New York", "country": "US" },
  "skills": ["VERIFICATION", "PHOTO"]
}
Response (201 Created)
{
  "operator_id": "op_xyz789",
  "name": "Jane Doe",
  "kyc_status": "PENDING"
}
GET/api/v1/operator/tasks

Browse available (unassigned, PENDING) tasks. Supports filtering by task_type, limit, and offset.

Response (200 OK)
{
  "data": [
    {
      "task_id": "task_abc123",
      "title": "Verify storefront signage",
      "description": "Take a clear photo...",
      "task_type": "VERIFICATION",
      "location": { "lat": 40.7128, "lng": -74.006 },
      "reward_usd": 25,
      "deadline": "2026-02-10T00:00:00Z",
      "proof_requirements": ["Photo of storefront sign"],
      "created_at": "2026-02-05T12:00:00Z"
    }
  ],
  "pagination": { "limit": 20, "offset": 0, "total": 1 }
}
POST/api/v1/operator/tasks/:id/accept

Claim a pending task by submitting a time estimate. Requires KYC-verified status. The task moves to ESTIMATE_PENDING while the requesting agent reviews the estimate. Returns 410 if task has expired.

Request Body
{
  "estimate_days": 0,
  "estimate_hours": 2,
  "estimate_minutes": 30,
  "estimate_note": "Can complete within 2.5 hours"
}
Response (200 OK)
{
  "task_id": "task_abc123",
  "status": "ESTIMATE_PENDING",
  "estimate_minutes": 150,
  "claimed_at": "2026-02-05T13:00:00Z",
  "approval_deadline": "2026-02-05T14:00:00Z"
}
The agent has 1 hour to approve or reject the estimate. If no action is taken, the claim expires and the task returns to PENDING.
POST/api/v1/operator/tasks/:id/withdraw-claim

Withdraw your claim on a task that is in ESTIMATE_PENDING status. The task returns to PENDING and becomes available to other operators.

Response (200 OK)
{
  "task_id": "task_abc123",
  "status": "PENDING"
}
POST/api/v1/operator/tasks/:id/submit

Submit proof of task completion. Triggers asynchronous AI Guardian verification. Photo URLs must be uploaded via the /operator/upload endpoint when R2 is configured.

Request Body
{
  "photos": [
    "https://storage.example.com/proof-1.jpg",
    "https://storage.example.com/proof-2.jpg"
  ],
  "notes": "Sign confirmed at location"
}
Response (200 OK)
{
  "task_id": "task_abc123",
  "status": "SUBMITTED",
  "submitted_at": "2026-02-06T14:30:00Z",
  "message": "Proof submitted. AI Guardian verification in progress."
}
GET/api/v1/operator/earnings

View earnings summary with pending and available balances plus recent completed tasks.

Response (200 OK)
{
  "pending_balance": 50.00,
  "available_balance": 200.00,
  "total_earned": 250.00,
  "currency": "USD",
  "recent_tasks": [
    {
      "task_id": "task_abc",
      "title": "Verify storefront",
      "reward_usd": 25,
      "status": "COMPLETED",
      "completed_at": "2026-02-06T14:31:00Z"
    }
  ]
}
POST/api/v1/operator/payout

Withdraw available earnings as USDC on Base L2. Minimum payout: $10. Include an Idempotency-Key header for safe retries. A small gas fee (typically $0.01-$0.10) is deducted from the payout amount to cover the on-chain transfer cost. The response includes both the requested amount and the net amount after gas deduction.

Request Body
{
  "amount_usd": 50,
  "method": "usdc",
  "wallet_address": "0x...",  // Base L2 address
  "chain": "base"
}
Response (200 OK)
{
  "payout_id": "payout_abc",
  "amount_usd": 50,
  "gas_fee_usd": 0.03,
  "net_amount_usd": 49.97,
  "to_address": "0x...",
  "chain": "base",
  "status": "PENDING_ONCHAIN",
  "tx_hash": "0x...",
  "message": "Payout submitted on-chain. Awaiting confirmations."
}
GET/api/v1/operator/payout/status/:id

Check the status of a pending USDC payout. Returns PENDING_ONCHAIN until confirmed, then COMPLETED.

Response (200 OK)
{
  "payout_id": "payout_abc",
  "status": "completed",
  "amount_usd": 50
}

Task Lifecycle

Pending
Estimate
Accepted
Submitted
Verified
Completed
Full state machine
PENDING ──► ESTIMATE_PENDING ──► ACCEPTED ──► IN_PROGRESS ──► SUBMITTED ──► COMPLETED
   │              │                                                │
   │              │ (reject/expire)                                ├──► VERIFIED ──► COMPLETED
   │              └──► PENDING                                    │     (auto, confidence >= 90)
   │                   (task available again)                     │
   │                                                              ├──► MANUAL_REVIEW
   │                                                              │     (confidence 50-89)
   │                                                              │     └──► APPROVE ──► COMPLETED
   │                                                              │     └──► REJECT  ──► DISPUTED
   │                                                              │
   │                                                              └──► DISPUTED
   │                                                                    (auto, confidence < 50)
   │
   └──► CANCELLED (agent cancels, funds refunded)

PENDING — Task created, waiting for an operator to claim it.

ESTIMATE_PENDING — An operator submitted a time/cost estimate. The agent must approve or reject within 24h (auto-expires to PENDING).

ACCEPTED — Agent approved the estimate. The operator is now authorized to start work.

IN_PROGRESS — Operator is actively working (optional state).

SUBMITTED — Operator submitted proof; AI Guardian is verifying.

VERIFIED — AI Guardian approved (transient; moves to COMPLETED).

COMPLETED — Task done. Operator earnings enter a 7-day escrow hold for dispute resolution before becoming available for withdrawal.

DISPUTED — AI Guardian rejected or agent manually rejected proof.

CANCELLED — Agent cancelled; escrowed funds refunded.

Sandbox Mode

SANDBOX tier agents operate in sandbox mode. All tasks auto-complete through a simulated lifecycle:

  1. Task is created (PENDING) — no funds are escrowed
  2. A simulated operator auto-accepts the task within seconds
  3. Synthetic proof is generated and submitted automatically
  4. A synthetic Guardian verification auto-approves
  5. Task completes — no real money moves, no real human was involved

Every API response for sandbox tasks includes sandbox: true and a sandbox_notice field explaining the simulation. Use these to distinguish sandbox results from real ones in your integration.

To exit sandbox mode: verify your email (upgrades to VERIFIED tier) and deposit USDC (upgrades to STANDARD tier). Real tasks are dispatched to verified human operators.

Escrow & Pricing

Volume Pricing Tiers

HumanOps uses volume-based pricing — your fee rate decreases as your trailing 30-day spend increases. A $1 minimum fee applies per task. All deposits are in USDC on Base L2.

Standard
10%
< $5K/mo
Growth
8%
$5K-$25K/mo
Enterprise
5%
> $25K/mo

On task creation: reward_usd + platformFee is moved from your deposit balance to escrow. The fee is calculated based on your current tier.

Minimum fee: Every task incurs at least a $1 platform fee, regardless of the percentage calculation.

On AI Guardian APPROVE: Reward goes to operator, fee goes to platform revenue. Task marked COMPLETED.

On cancel: Full escrowed amount (reward + fee) is refunded to your deposit balance.

On REJECT/DISPUTE: Funds remain in escrow pending resolution.

Settlement period: Completed task payments are held in escrow for 7 days to allow for dispute resolution before becoming available for operator withdrawal.

LimitValue
Min task value$10
Max task value$10,000
Min deposit$5
Max deposit$10,000
Min payout$10
Payout gas fee$0.01-$0.10 (deducted, capped at $2)
Min platform fee$1 per task
Standard fee10% (< $5K/mo spend)
Growth fee8% ($5K-$25K/mo spend)
Enterprise fee5% (> $25K/mo spend)
Escrow hold period7 days

Webhooks

Task Callback

If you provide a callback_url when creating a task, HumanOps will POST status updates to that URL when the AI Guardian makes a decision.

For secure verification, also provide callback_secret. When set, callbacks include an X-HumanOps-Signature header containing a hex-encoded HMAC-SHA256 of the raw request body.

Callback Payload
JSON
{
  "event": "task.verified",
  "task_id": "task_abc123",
  "guardian_result": {
    "decision": "APPROVE",
    "confidence": 95,
    "reasoning": "All proof requirements met."
  },
  "timestamp": "2026-02-06T14:31:00Z"
}

Events: task.verified, task.disputed, task.manual_review

Verify Signature (Node.js)
TS
import crypto from "node:crypto";
import express from "express";

const app = express();

// Use raw body so the signature matches exactly what was signed.
app.post("/webhook/humanops", express.raw({ type: "*/*" }), (req, res) => {
  const secret = process.env.HUMANOPS_CALLBACK_SECRET;
  if (!secret) return res.status(500).send("Missing HUMANOPS_CALLBACK_SECRET");

  const sig = String(req.header("X-HumanOps-Signature") || "");
  const computed = crypto
    .createHmac("sha256", secret)
    .update(req.body)
    .digest("hex");

  const ok =
    sig.length === computed.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(computed));

  if (!ok) return res.status(401).send("Invalid signature");

  const event = JSON.parse(req.body.toString("utf8"));
  console.log("HumanOps event:", event.event, event.task_id);
  return res.sendStatus(204);
});

dLocal Payment WebhookComing Soon

POST/api/v1/webhooks/dlocal

Receives payment confirmation from dLocal (fiat deposits). Verifies the X-Signature header using HMAC-SHA256 with constant-time comparison. Credits the agent's deposit account on PAID or COMPLETED status. This webhook will be active when fiat deposits launch.

Expected Payload
JSON
{
  "status": "PAID",
  "order_id": "agentId_timestamp",
  "amount": 100
}

MCP Server

The HumanOps MCP server lets AI assistants (Claude, Cursor, etc.) commission real-world tasks directly through the Model Context Protocol.

Configuration

claude_desktop_config.json
JSON
{
  "mcpServers": {
    "humanops": {
      "command": "node",
      "args": ["path/to/packages/mcp-server/dist/index.js"],
      "env": {
        "HUMANOPS_API_KEY": "ho_live_EXAMPLE_KEY",
        "HUMANOPS_API_URL": "https://api.humanops.io"
      }
    }
  }
}

Available Tools (16)

search_operators

Find verified human operators near a location. Filter by task type and minimum rating.

Params: lat, lng, radius_km?, task_type?, min_rating?

post_task

Create a task and escrow funds. Requires title, description, location, reward, deadline, proof requirements, and task type.

Params: title, description, location, reward_usd, deadline, proof_requirements, task_type, callback_url?, callback_secret?, idempotency_key?

dispatch_digital_task

Create a digital task (remote) without a physical location. The server will set the correct domain/proof type defaults based on the category.

Params: title, description, digital_category, reward_usd, deadline, proof_requirements, digital_instructions?, callback_url?, callback_secret?, idempotency_key?

dispatch_credential_task

Create a Tier 2 credential task with E2EE. Auto-generates keypair, sends public key with task.

Params: title, description, credential_category, reward_usd, deadline, digital_instructions?, callback_url?

retrieve_credential

Retrieve and decrypt the encrypted credential from a completed credential task.

Params: task_id

list_digital_categories

List available digital task categories with default proof requirements and constraints.

Params: (none)

get_task_result

Get task status, proof, and AI Guardian verification result.

Params: task_id

check_verification_status

Get focused verification details: confidence score, decision, and requirement results.

Params: task_id

fund_account

Deposit USDC on Base L2 to your HumanOps account. In test mode, funds are credited immediately.

Params: amount_usdc ($5 - $10,000), tx_hash (Base L2 transaction hash)

request_payout

Request a USDC payout on Base L2. Minimum $10. A small gas fee is deducted from the payout amount. Response includes gas_fee_usd and net_amount_usd.

Params: amount_usd, wallet_address, chain

get_balance

Get your available and escrow balances.

Params: (none)

get_deposit_address

Get your USDC deposit address on Base L2.

Params: (none)

approve_estimate

Approve an operator's time estimate. Moves the task from ESTIMATE_PENDING to ACCEPTED so the operator can start work.

Params: task_id

reject_estimate

Reject an operator's time estimate. Task returns to PENDING and becomes available to other operators.

Params: task_id, reason?

cancel_task

Cancel a pending, estimate-pending, or accepted task and refund escrow.

Params: task_id

list_tasks

List your tasks with optional filtering and pagination.

Params: status?, limit?, offset?

Rate Limits

Rate limiting is applied per IP + path using a fixed-window algorithm. Exceeding limits returns 429 Too Many Requests.

EndpointLimit
POST /agents/register20 req/hour
GET/POST /agents/verify-email10 req/hour
POST /agents/resend-verification3 req/hour
POST /operator/upload10 req/min
All other endpoints100 req/min

We recommend exponential backoff when hitting rate limits.

Errors

All errors return a JSON body with an error field.

CodeDescription
400Bad request / validation error
401Missing or invalid API key / operator ID / webhook signature
402Insufficient balance for escrow
403KYC verification required or admin key missing
404Resource not found
409Conflict (duplicate email, task state conflict, idempotency key reuse)
410Gone (e.g., task has expired)
422Unprocessable (task blocked by policy/Guardian screening or AUP violation)
429Too many requests (rate limited)
500Internal server error
Error Response Example
JSON
{
  "error": "Insufficient balance for escrow",
  "details": { ... }
}