{
  "openapi": "3.1.0",
  "info": {
    "title": "Faqtic Proposal Request API",
    "version": "1.0.0",
    "description": "Submit and track requests for a Factorial implementation proposal from Faqtic on behalf of a person who asked for one. Every request is confirmed by the contact via email before it is processed. No binding quotes, contracts or purchases are created.",
    "contact": { "name": "Faqtic", "email": "marvin@faqtic.co", "url": "https://faqtic.co/for-agents" }
  },
  "servers": [{ "url": "https://erzbmzxtdjinuivizctx.supabase.co/functions/v1" }],
  "paths": {
    "/proposal-requests": {
      "post": {
        "operationId": "submitProposalRequest",
        "summary": "Submit a proposal request",
        "parameters": [
          { "name": "Idempotency-Key", "in": "header", "required": false, "schema": { "type": "string", "minLength": 8, "maxLength": 200 }, "description": "Retries with the same key return the original result." }
        ],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProposalRequest" } } } },
        "responses": {
          "201": { "description": "Created, pending email confirmation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProposalCreated" } } } },
          "200": { "description": "Idempotent replay of an earlier request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProposalStatus" } } } },
          "400": { "$ref": "#/components/responses/Error" },
          "409": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "500": { "$ref": "#/components/responses/Error" }
        }
      },
      "get": {
        "operationId": "getProposalRequestStatus",
        "summary": "Get the status of a proposal request",
        "parameters": [
          { "name": "id", "in": "query", "required": true, "schema": { "type": "string", "pattern": "^FQ-[A-Z0-9]{8}$" } },
          { "name": "X-Status-Token", "in": "header", "required": true, "schema": { "type": "string" }, "description": "Private token returned at submission." }
        ],
        "responses": {
          "200": { "description": "Status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProposalStatus" } } } },
          "401": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ProposalRequest": {
        "type": "object",
        "required": ["company_name", "country", "employee_count", "contact_name", "business_email", "user_authorisation_declared"],
        "properties": {
          "company_name": { "type": "string", "maxLength": 200 },
          "company_website": { "type": "string", "format": "uri", "maxLength": 300 },
          "country": { "type": "string", "maxLength": 100 },
          "employee_count": { "type": "integer", "minimum": 1, "maximum": 100000 },
          "industry": { "type": "string", "maxLength": 120 },
          "contact_name": { "type": "string", "maxLength": 120 },
          "business_email": { "type": "string", "format": "email", "description": "Business address. Personal domains are rejected." },
          "job_title": { "type": "string", "maxLength": 120 },
          "current_hr_system": { "type": "string", "maxLength": 120 },
          "modules_required": { "type": "array", "maxItems": 20, "items": { "type": "string", "maxLength": 60 } },
          "main_challenges": { "type": "string", "maxLength": 3000 },
          "timeframe": { "type": "string", "maxLength": 120 },
          "comments": { "type": "string", "maxLength": 3000 },
          "request_source": { "type": "string", "enum": ["ai_agent", "website", "other"], "default": "ai_agent" },
          "agent_name": { "type": "string", "maxLength": 120 },
          "user_authorisation_declared": { "type": "boolean", "const": true, "description": "The contact asked for this request. Not treated as verified consent; the contact confirms by email." }
        }
      },
      "ProposalStatus": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "status": { "type": "string", "enum": ["pending_confirmation", "confirmed"] },
          "duplicate": { "type": "boolean" },
          "submitted_at": { "type": "string", "format": "date-time" },
          "message": { "type": "string" },
          "next_steps": { "type": "array", "items": { "type": "string" } }
        }
      },
      "ProposalCreated": {
        "allOf": [
          { "$ref": "#/components/schemas/ProposalStatus" },
          { "type": "object", "properties": { "status_token": { "type": "string" }, "status_url": { "type": "string" }, "documentation": { "type": "string" } } }
        ]
      },
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "object", "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "details": { "type": "object", "additionalProperties": { "type": "string" } } } } }
      }
    },
    "responses": {
      "Error": { "description": "Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  }
}
