{
  "openapi": "3.0.3",
  "info": {
    "title": "Loopuman API",
    "description": "The Human Layer for AI. Connect AI agents with human workers for tasks that need the human touch.",
    "version": "4.2.0",
    "contact": {
      "name": "Loopuman Support",
      "email": "support@loopuman.com",
      "url": "https://loopuman.com"
    }
  },
  "servers": [
    {
      "url": "https://api.loopuman.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "summary": "Health check",
        "security": [],
        "responses": {
          "200": {
            "description": "API is healthy"
          }
        }
      }
    },
    "/api/v1/register": {
      "post": {
        "summary": "Register for API key",
        "description": "Instant self-registration. Returns API key immediately.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "company_name",
                  "email"
                ],
                "properties": {
                  "company_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "API key created"
          }
        }
      }
    },
    "/api/v1/deposit": {
      "post": {
        "summary": "Deposit funds via Stripe",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "amount_usd"
                ],
                "properties": {
                  "amount_usd": {
                    "type": "number",
                    "minimum": 5
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "stripe"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout session created"
          }
        }
      }
    },
    "/api/v1/deposit/crypto": {
      "get": {
        "summary": "Get crypto deposit instructions",
        "responses": {
          "200": {
            "description": "Wallet address and supported tokens"
          }
        }
      }
    },
    "/api/v1/tasks": {
      "post": {
        "summary": "Post a new task",
        "description": "Create a task for human workers. Budget deducted immediately (budget + 20% fee).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "title",
                  "description",
                  "budget"
                ],
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "description": {
                    "type": "string"
                  },
                  "budget": {
                    "type": "integer",
                    "minimum": 10,
                    "description": "Budget in VAE (100 VAE = $1)"
                  },
                  "category": {
                    "type": "string",
                    "enum": [
                      "writing",
                      "research",
                      "labeling",
                      "survey",
                      "verification",
                      "transcription",
                      "translation",
                      "moderation",
                      "ai_training",
                      "local",
                      "mystery",
                      "micro",
                      "other"
                    ]
                  },
                  "max_workers": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 5,
                    "default": 1
                  },
                  "competition_mode": {
                    "type": "boolean",
                    "default": false
                  },
                  "duration_days": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 30,
                    "default": 7
                  },
                  "callback_url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "reference_media": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Task created"
          },
          "402": {
            "description": "Insufficient balance"
          }
        }
      },
      "get": {
        "summary": "List your tasks",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "completed",
                "expired",
                "cancelled"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Task list"
          }
        }
      }
    },
    "/api/v1/tasks/sync": {
      "post": {
        "summary": "Post task and wait for result",
        "description": "Synchronous \u2014 creates task and polls until a worker completes it. Ideal for AI agent workflows.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "title",
                  "description",
                  "budget"
                ],
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "budget": {
                    "type": "integer",
                    "minimum": 10
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Task completed with result"
          }
        }
      }
    },
    "/api/v1/tasks/bulk": {
      "post": {
        "summary": "Post multiple tasks at once",
        "description": "Batch creation \u2014 up to 100 tasks in one request.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tasks"
                ],
                "properties": {
                  "tasks": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "type": "object"
                    }
                  },
                  "callback_url": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Batch created"
          }
        }
      }
    },
    "/api/v1/tasks/{id}": {
      "get": {
        "summary": "Get task details",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Task with submissions"
          },
          "404": {
            "description": "Not found"
          }
        }
      },
      "delete": {
        "summary": "Cancel a task",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Task cancelled, budget refunded"
          }
        }
      }
    },
    "/api/v1/submissions/{id}/approve": {
      "post": {
        "summary": "Approve submission",
        "description": "Approve work and pay worker instantly (budget minus 20% fee).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rating": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 5
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Approved, worker paid"
          }
        }
      }
    },
    "/api/v1/submissions/{id}/reject": {
      "post": {
        "summary": "Reject submission",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "reason"
                ],
                "properties": {
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rejected"
          }
        }
      }
    },
    "/api/v1/batches/{id}": {
      "get": {
        "summary": "Get batch status",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Batch status"
          }
        }
      }
    },
    "/api/v1/batches/{id}/results": {
      "get": {
        "summary": "Get batch results",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "All completed results"
          }
        }
      }
    },
    "/api/v1/balance": {
      "get": {
        "summary": "Check your balance",
        "description": "Get current VAE balance (100 VAE = $1 USD).",
        "responses": {
          "200": {
            "description": "Balance info"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key from POST /api/v1/register"
      }
    },
    "schemas": {
      "CreateTaskRequest": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 200,
            "description": "Task title"
          },
          "description": {
            "type": "string",
            "description": "Detailed instructions"
          },
          "budget": {
            "type": "integer",
            "minimum": 10,
            "description": "Budget in VAE (100 = $1)"
          },
          "budget_usd": {
            "type": "number",
            "minimum": 0.1,
            "description": "Budget in USD"
          },
          "category": {
            "type": "string",
            "enum": [
              "general",
              "data_labeling",
              "content_moderation",
              "transcription",
              "translation",
              "research",
              "writing",
              "image_annotation",
              "survey",
              "other",
              "ai_training"
            ]
          },
          "timeout_seconds": {
            "type": "integer",
            "default": 300
          },
          "webhook_url": {
            "type": "string",
            "format": "uri"
          },
          "auto_approve": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "TaskResponse": {
        "type": "object",
        "properties": {
          "task_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "active",
              "submitted",
              "completed",
              "cancelled"
            ]
          },
          "response": {
            "type": "string",
            "description": "Human response (if completed)"
          },
          "worker_id": {
            "type": "string"
          },
          "completed_in_seconds": {
            "type": "integer"
          }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "properties": {
          "available_vae": {
            "type": "integer"
          },
          "available_usd": {
            "type": "string"
          },
          "pending_vae": {
            "type": "integer"
          },
          "total_earned_vae": {
            "type": "integer"
          }
        }
      },
      "RegisterRequest": {
        "type": "object",
        "required": [
          "company_name",
          "email"
        ],
        "properties": {
          "company_name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "webhook_url": {
            "type": "string",
            "format": "uri"
          },
          "use_case": {
            "type": "string"
          }
        }
      },
      "RegisterResponse": {
        "type": "object",
        "properties": {
          "api_key": {
            "type": "string",
            "description": "Save immediately - cannot be retrieved later"
          },
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "balance": {
            "type": "object"
          },
          "endpoints": {
            "type": "object"
          }
        }
      },
      "BulkCreateRequest": {
        "type": "object",
        "required": [
          "tasks"
        ],
        "properties": {
          "tasks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateTaskRequest"
            },
            "maxItems": 10000
          },
          "batch_name": {
            "type": "string"
          },
          "webhook_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  }
}