{
  "openapi": "3.1.0",
  "info": {
    "title": "A1 Lab Contact API",
    "version": "1.0.0",
    "description": "Public contact endpoint for A1 Lab (a1lab.com.br). Agents can submit a short description of a process or idea. This is not a product API. Turnstile is required for browser submissions; agents should prefer email if they cannot complete captcha.\n\nVersioning: the current API is v1. Canonical path is POST /v1/contact. POST /api/contact is a stable alias for the site form. Breaking changes ship under /v2. Deprecated versions receive Deprecation: true and Sunset (HTTP-date) at least 90 days before removal. Responses include API-Version: 1.\n\nRate limits: 30 requests per hour per IP. Responses include RateLimit, RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset. HTTP 429 includes Retry-After.",
    "contact": {
      "name": "A1 Lab",
      "email": "contato@a1lab.com.br",
      "url": "https://a1lab.com.br/docs/"
    }
  },
  "servers": [
    { "url": "https://a1lab.com.br", "description": "Portuguese site" },
    { "url": "https://thea1lab.com", "description": "English site" }
  ],
  "paths": {
    "/v1/contact": {
      "$ref": "#/paths/~1api~1contact"
    },
    "/api/contact": {
      "post": {
        "operationId": "submitContact",
        "summary": "Submit a contact request",
        "description": "Send a JSON body with name, email, subject, and message. Optional company and stage. Browser clients must include a Cloudflare Turnstile token.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ContactRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message accepted",
            "headers": {
              "API-Version": { "$ref": "#/components/headers/ApiVersion" },
              "RateLimit": { "$ref": "#/components/headers/RateLimit" },
              "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ContactSuccess" }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "403": {
            "description": "Captcha failed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "405": {
            "description": "Method not allowed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "headers": {
              "Retry-After": { "$ref": "#/components/headers/RetryAfter" },
              "RateLimit": { "$ref": "#/components/headers/RateLimit" }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "500": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "ApiVersion": {
        "description": "Major API version of this response.",
        "schema": { "type": "string", "example": "1" }
      },
      "RateLimit": {
        "description": "RFC rate-limit header: limit, remaining, reset (seconds).",
        "schema": { "type": "string", "example": "limit=30, remaining=29, reset=3600" }
      },
      "RateLimitPolicy": {
        "description": "Quota and window in seconds.",
        "schema": { "type": "string", "example": "30;w=3600" }
      },
      "RetryAfter": {
        "description": "Seconds until a 429 client may retry.",
        "schema": { "type": "integer" }
      }
    },
    "schemas": {
      "ContactRequest": {
        "type": "object",
        "required": ["name", "email", "subject", "message"],
        "properties": {
          "name": { "type": "string", "maxLength": 120 },
          "email": { "type": "string", "format": "email", "maxLength": 254 },
          "company": { "type": "string", "maxLength": 120 },
          "subject": { "type": "string", "maxLength": 120 },
          "stage": { "type": "string", "maxLength": 120 },
          "message": { "type": "string", "maxLength": 2000 },
          "cf-turnstile-response": {
            "type": "string",
            "description": "Cloudflare Turnstile token. Required for browser form posts."
          }
        }
      },
      "ContactSuccess": {
        "type": "object",
        "required": ["ok"],
        "properties": {
          "ok": { "type": "boolean", "const": true }
        }
      },
      "Error": {
        "type": "object",
        "required": ["ok", "code", "message", "hint"],
        "properties": {
          "ok": { "type": "boolean", "const": false },
          "error": { "type": "string", "description": "Same as code, kept for the site form." },
          "code": { "type": "string" },
          "message": { "type": "string" },
          "hint": { "type": "string" }
        }
      }
    }
  }
}
