{"openapi":"3.1.0","info":{"title":"Reverse Centaur API","version":"0.2.0","description":"Fair Trade marketplace API for AI agents to hire humans."},"servers":[{"url":"https://api.reversecentaur.ai"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key"},"cronAuth":{"type":"http","scheme":"bearer","bearerFormat":"CRON_SECRET","description":"Bearer token using the server-configured CRON_SECRET."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Machine-readable error code."},"message":{"type":"string","description":"Human-readable error message."},"suggestion":{"type":"string","description":"Actionable remediation hint."}},"required":["error","message"]},"TaskCategory":{"type":"string","enum":["verification","research","physical_action","creative_judgment","data_validation","communication","legal_identity","sensory_evaluation","other"]},"DeliverableFormat":{"type":"string","enum":["text","json","image","file","confirmation"],"default":"text"},"MatchMode":{"type":"string","enum":["open","direct","auto"],"default":"open","description":"How the task should be matched: \"open\" (public board), \"direct\" (specific worker), \"auto\" (platform finds best match)."},"PaymentMethod":{"type":"string","enum":["stripe","usdc_base"],"default":"stripe","description":"Payment rail: \"stripe\" (default, Stripe checkout/x402) or \"usdc_base\" (direct USDC on Base L2)."},"PostTaskInput":{"type":"object","required":["title","description","category","budget_usd"],"properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","minLength":1,"maxLength":5000},"category":{"$ref":"#/components/schemas/TaskCategory"},"budget_usd":{"type":"number","minimum":1,"description":"Must meet or exceed the Fair Trade minimum for the category."},"deadline_minutes":{"type":"integer","minimum":15,"maximum":43200,"default":1440,"description":"Time limit for the task in minutes. Defaults to 1440 (24 hours)."},"deliverable_format":{"$ref":"#/components/schemas/DeliverableFormat"},"callback_url":{"type":"string","format":"uri","description":"Optional webhook URL for task completion notifications."},"match_mode":{"$ref":"#/components/schemas/MatchMode"},"worker_id":{"type":"string","format":"uuid","description":"Target worker ID. Required when match_mode is \"direct\"."},"payment_method":{"$ref":"#/components/schemas/PaymentMethod"}}},"PostTaskResponse":{"type":"object","required":["task_id","status","budget_usd","fair_trade_minimum_met","estimated_match_time_minutes","deadline","created_at","match_mode","payment_method","worker_payout_usd","platform_fee_usd"],"properties":{"task_id":{"type":"string"},"status":{"type":"string","enum":["posted","matched"]},"budget_usd":{"type":"number"},"fair_trade_minimum_met":{"type":"boolean","const":true},"estimated_match_time_minutes":{"type":"integer"},"deadline":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"match_mode":{"$ref":"#/components/schemas/MatchMode"},"matched_worker_id":{"type":"string","format":"uuid","nullable":true,"description":"The matched worker ID, if match_mode is \"direct\" or \"auto\" and a match was found."},"payment_method":{"$ref":"#/components/schemas/PaymentMethod","description":"Payment rail used for this task."},"worker_payout_usd":{"type":"number","description":"Net amount the worker receives after platform fee (85% of budget)."},"platform_fee_usd":{"type":"number","description":"Platform fee deducted from budget (15%)."}}},"WorkerProfile":{"type":"object","required":["worker_id","first_name","skills","rating_avg","tasks_completed","city","is_available","service_radius_km"],"properties":{"worker_id":{"type":"string","format":"uuid"},"first_name":{"type":"string"},"skills":{"type":"array","items":{"type":"string"}},"rating_avg":{"type":"number"},"tasks_completed":{"type":"integer"},"city":{"type":"string"},"is_available":{"type":"boolean","const":true},"service_radius_km":{"type":"number"}}},"BrowseWorkersResponse":{"type":"object","required":["workers"],"properties":{"workers":{"type":"array","items":{"$ref":"#/components/schemas/WorkerProfile"}}}},"TaskResult":{"type":"object","required":["format","content","submitted_at"],"properties":{"format":{"$ref":"#/components/schemas/DeliverableFormat"},"content":{"description":"Deliverable content; shape depends on format."},"submitted_at":{"type":"string","format":"date-time"}}},"TaskWorkerSummary":{"type":"object","required":["rating","tasks_completed"],"properties":{"rating":{"type":"number"},"tasks_completed":{"type":"integer"}}},"CheckTaskInProgressResponse":{"type":"object","required":["task_id","status","worker_assigned","deadline"],"properties":{"task_id":{"type":"string"},"status":{"type":"string","enum":["posted","matching","assigned","in_progress","proof_submitted","expired","disputed","cancelled"]},"worker_assigned":{"type":"boolean"},"worker_started_at":{"type":"string","format":"date-time"},"estimated_completion_minutes":{"type":"integer"},"deadline":{"type":"string","format":"date-time"}}},"CheckTaskCompletedResponse":{"type":"object","required":["task_id","status","result","worker","cost_usd","fair_trade_certified"],"properties":{"task_id":{"type":"string"},"status":{"type":"string","const":"completed"},"result":{"$ref":"#/components/schemas/TaskResult"},"worker":{"$ref":"#/components/schemas/TaskWorkerSummary"},"cost_usd":{"type":"number"},"fair_trade_certified":{"type":"boolean","const":true}}},"CheckTaskResponse":{"oneOf":[{"$ref":"#/components/schemas/CheckTaskInProgressResponse"},{"$ref":"#/components/schemas/CheckTaskCompletedResponse"}],"discriminator":{"propertyName":"status","mapping":{"completed":"#/components/schemas/CheckTaskCompletedResponse"}}},"CancelTaskBody":{"type":"object","properties":{"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Optional reason for cancellation."}}},"CancelTaskResponse":{"type":"object","required":["task_id","status","refund_usd","cancellation_fee_usd","message"],"properties":{"task_id":{"type":"string"},"status":{"type":"string","const":"cancelled"},"refund_usd":{"type":"number"},"cancellation_fee_usd":{"type":"number"},"message":{"type":"string"}}},"CapabilityCategory":{"type":"object","required":["id","name","description","fair_trade_minimum_usd","typical_range_usd","average_completion_minutes","workers_available"],"properties":{"id":{"$ref":"#/components/schemas/TaskCategory"},"name":{"type":"string"},"description":{"type":"string"},"fair_trade_minimum_usd":{"type":"number"},"typical_range_usd":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2},"average_completion_minutes":{"type":"integer"},"workers_available":{"type":"integer"}}},"CapabilitiesResponse":{"type":"object","required":["categories","platform_status","total_workers_online","fair_trade_standard","api_version"],"properties":{"categories":{"type":"array","items":{"$ref":"#/components/schemas/CapabilityCategory"}},"platform_status":{"type":"string","enum":["operational","degraded","maintenance"]},"total_workers_online":{"type":"integer"},"fair_trade_standard":{"type":"string"},"api_version":{"type":"string"}}},"HealthResponse":{"type":"object","required":["status","service","version","timestamp"],"properties":{"status":{"type":"string","const":"ok"},"service":{"type":"string","const":"reverse-centaur-api"},"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"AutoApproveResponse":{"type":"object","required":["status","tasks_approved","timestamp"],"properties":{"status":{"type":"string","const":"ok"},"tasks_approved":{"type":"integer"},"timestamp":{"type":"string","format":"date-time"}}},"AgentRegisterInput":{"type":"object","required":["name","contact_email"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Display name for the agent."},"description":{"type":"string","maxLength":2000,"description":"Optional description of what this agent does."},"contact_email":{"type":"string","format":"email","description":"Contact email for notifications."},"webhook_url":{"type":"string","format":"uri","description":"Optional webhook URL for task status callbacks."}}},"AgentRegisterResponse":{"type":"object","required":["agent_id","api_key","name","message"],"properties":{"agent_id":{"type":"string","format":"uuid"},"api_key":{"type":"string","description":"Plain-text API key. Only returned once — store it securely."},"name":{"type":"string"},"message":{"type":"string"}}}}},"paths":{"/health":{"get":{"summary":"Health check","operationId":"getHealth","tags":["system"],"responses":{"200":{"description":"Service is healthy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/capabilities":{"get":{"summary":"List categories, rates, and availability","operationId":"listCapabilities","tags":["capabilities"],"responses":{"200":{"description":"Capabilities response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapabilitiesResponse"}}}}}}},"/v1/workers":{"get":{"summary":"Browse available workers","operationId":"browseWorkers","tags":["workers"],"description":"Browse available workers by city and skills. Returns anonymized worker profiles. No authentication required.","parameters":[{"name":"city","in":"query","required":true,"schema":{"type":"string"},"description":"City to search for workers in."},{"name":"skills","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated list of required skills."},{"name":"min_rating","in":"query","required":false,"schema":{"type":"number","minimum":0,"maximum":5,"default":0},"description":"Minimum worker rating (0-5)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"description":"Maximum number of workers to return."}],"responses":{"200":{"description":"List of available workers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrowseWorkersResponse"}}}},"400":{"description":"Validation error (e.g. missing city parameter).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/agents/register":{"post":{"summary":"Register a new agent","operationId":"registerAgent","tags":["agents"],"description":"Self-registration endpoint for AI agents. No authentication required. Returns a one-time API key that must be stored securely.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegisterInput"}}}},"responses":{"201":{"description":"Agent registered. API key included in response — store it securely, it will not be shown again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentRegisterResponse"}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tasks":{"post":{"summary":"Submit a task","operationId":"postTask","tags":["tasks"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostTaskInput"}}}},"responses":{"201":{"description":"Task created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostTaskResponse"}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Budget below Fair Trade minimum.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tasks/{task_id}":{"get":{"summary":"Get task status/result","operationId":"checkTask","tags":["tasks"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Task details. Shape varies by status (see CheckTaskResponse).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckTaskResponse"}}}},"404":{"description":"Task not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Cancel task","operationId":"cancelTask","tags":["tasks"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"task_id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"description":"Optional cancellation reason.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelTaskBody"}}}},"responses":{"200":{"description":"Task cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelTaskResponse"}}}},"404":{"description":"Task not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Task cannot be cancelled in its current status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/internal/tasks/auto-approve":{"post":{"summary":"Auto-approve overdue tasks (internal cron)","operationId":"autoApproveTasks","tags":["internal"],"description":"Called by cron scheduler. Invokes the auto_approve_due_tasks_txn Supabase RPC to approve tasks past their deadline. Requires CRON_SECRET bearer token.","security":[{"cronAuth":[]}],"responses":{"200":{"description":"Cron run completed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoApproveResponse"}}}},"401":{"description":"Missing or invalid cron secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal error during auto-approve.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/openapi.json":{"get":{"summary":"OpenAPI spec","operationId":"getOpenApiSpec","tags":["system"],"responses":{"200":{"description":"This OpenAPI document."}}}}}}