{
  "openapi": "3.1.0",
  "info": {
    "title": "VA Heroes PH Public Content API",
    "version": "1.0.0",
    "summary": "Read-only access to VA Heroes PH public website content.",
    "description": "Public, unauthenticated API for the content published on the VA Heroes PH website: Hero Paths (training and sales career tracks), Hero Stories, impact statistics, published FAQs and organization information.\n\nRead endpoints expose only content already visible on https://www.vaheroesph.com. Write endpoints accept application and contact submissions; submitted data is stored privately and can never be read, listed, modified or deleted through this API. The embedded third-party application form on /careers continues to operate independently of these endpoints.\n\nEvery request and response object is defined once as a reusable JSON Schema (Draft 2020-12); the same definitions enforce server-side request validation and are published at /api/public/v1/schemas. All responses include an x-request-id header, repeated as error.requestId in error envelopes; browser CORS is limited to the VA Heroes PH origins.\n\nSecurity: no API keys, tokens or credentials are accepted or required, and any Authorization header is ignored. Reads are cacheable; write responses and errors are never cached. Write endpoints enforce schema validation (422), a 32 KB body limit (413), an invisible spam honeypot, idempotent de-duplication and a rate limit of 5 submissions per 10 minutes per client (429 with Retry-After).",
    "contact": {
      "name": "VA Heroes PH",
      "url": "https://www.vaheroesph.com/careers"
    }
  },
  "servers": [
    {
      "url": "https://www.vaheroesph.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Hero Paths",
      "description": "Read operations for the VA Heroes PH career and training paths."
    },
    {
      "name": "Community",
      "description": "Read operations for community proof: Hero Stories and impact statistics."
    },
    {
      "name": "System",
      "description": "Organization metadata, service health and the API specification itself."
    },
    {
      "name": "FAQs",
      "description": "Read operations for the published Frequently Asked Questions."
    },
    {
      "name": "Applications",
      "description": "Write operations for job applications submitted to VA Heroes PH."
    },
    {
      "name": "Contact",
      "description": "Write operations for general contact messages."
    }
  ],
  "paths": {
    "/api/public/v1/hero-paths": {
      "get": {
        "operationId": "getHeroPaths",
        "tags": [
          "Hero Paths"
        ],
        "summary": "List Hero Paths",
        "description": "READ. Returns every Hero Path published on the website, optionally filtered by type or featured flag.",
        "security": [],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter by path type.",
            "schema": {
              "type": "string",
              "enum": [
                "training",
                "sales"
              ]
            }
          },
          {
            "name": "featured",
            "in": "query",
            "required": false,
            "description": "Filter by featured flag.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of Hero Paths.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HeroPathList"
                },
                "examples": {
                  "featured": {
                    "summary": "Featured path only",
                    "value": {
                      "total": 1,
                      "count": 1,
                      "items": [
                        {
                          "slug": "general-va",
                          "name": "General VA",
                          "label": "Zero to Hero",
                          "tagline": "Starting from zero? Start here.",
                          "description": "Build your foundation and discover what it takes to become a professional Virtual Assistant.",
                          "intro": "The General VA path is the entry point for Filipinos with little or no VA experience.",
                          "highlights": [
                            "No experience required",
                            "Foundational remote work skills"
                          ],
                          "type": "training",
                          "featured": true,
                          "externalUrl": "https://vaheroesbootcamp.com/",
                          "url": "https://www.vaheroesph.com/hero-paths/general-va"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/public/v1/hero-paths/{slug}": {
      "get": {
        "operationId": "getHeroPath",
        "tags": [
          "Hero Paths"
        ],
        "summary": "Get a single Hero Path",
        "description": "READ. Returns one Hero Path by its URL slug.",
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Hero Path slug as used in the website URL.",
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9-]{1,64}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The requested Hero Path.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HeroPath"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/public/v1/hero-stories": {
      "get": {
        "operationId": "getHeroStories",
        "tags": [
          "Community"
        ],
        "summary": "List Hero Stories",
        "description": "READ. Returns the published Hero Story testimonials shown on the website.",
        "security": [],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of Hero Stories.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HeroStoryList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/public/v1/impact-stats": {
      "get": {
        "operationId": "getImpactStats",
        "tags": [
          "Community"
        ],
        "summary": "List impact statistics",
        "description": "READ. Returns the impact statistics displayed on the homepage.",
        "security": [],
        "responses": {
          "200": {
            "description": "A list of impact statistics.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImpactStatList"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/public/v1/organization": {
      "get": {
        "operationId": "getOrganization",
        "tags": [
          "System"
        ],
        "summary": "Get organization information",
        "description": "READ. Returns public organization details: name, website, logo, description, social profiles and the public application page URL.",
        "security": [],
        "responses": {
          "200": {
            "description": "Organization information.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SiteInfo"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/public/v1/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "System"
        ],
        "summary": "Service health and readiness check",
        "description": "READ. Liveness by default. With ?ready=true the endpoint also probes the database dependency and returns 200 when ready or 503 when degraded. Exposes status words, booleans and a latency figure only — never hostnames, connection strings, environment values or error details.",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "A dependency is unavailable; the service is degraded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "ready",
            "in": "query",
            "required": false,
            "description": "Set to true to run the readiness probe (API + database).",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          }
        ]
      }
    },
    "/api/public/v1/openapi": {
      "get": {
        "operationId": "getOpenApiSpec",
        "tags": [
          "System"
        ],
        "summary": "Get this OpenAPI specification",
        "description": "READ. Returns this OpenAPI 3.1 document as JSON for API clients, AI agents and MCP servers.",
        "security": [],
        "responses": {
          "200": {
            "description": "The OpenAPI document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/public/v1/faqs": {
      "get": {
        "operationId": "searchFaqs",
        "tags": [
          "FAQs"
        ],
        "summary": "List or search FAQs",
        "description": "READ. Returns the published Frequently Asked Questions from the About VA Heroes page. Optionally filtered by a case-insensitive substring match on question and answer text.",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Case-insensitive search term matched against question and answer text.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "experience"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of items to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A list of FAQ entries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FaqList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/public/v1/applications": {
      "post": {
        "operationId": "submitApplication",
        "tags": [
          "Applications"
        ],
        "summary": "Submit an application",
        "description": "WRITE. Validates and stores a job application. Rate limited to 5 submissions per 10 minutes per client, protected by an anti-spam honeypot field, and idempotent: resubmitting identical content returns the original receipt with 200 instead of creating a duplicate. Submissions are stored privately and are never readable through this API.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplicationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "An identical submission already existed; the original receipt is returned (idempotent).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmissionReceipt"
                }
              }
            }
          },
          "201": {
            "description": "Submission stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmissionReceipt"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "413": {
            "description": "Request body larger than 32 KB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "504": {
            "description": "The backend did not respond in time.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/contact": {
      "post": {
        "operationId": "submitContactRequest",
        "tags": [
          "Contact"
        ],
        "summary": "Submit a contact request",
        "description": "WRITE. Validates and stores a general contact message. Same rate limiting, honeypot and idempotency behaviour as application submissions. Messages are stored privately and are never readable through this API.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "An identical submission already existed; the original receipt is returned (idempotent).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmissionReceipt"
                }
              }
            }
          },
          "201": {
            "description": "Submission stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmissionReceipt"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "413": {
            "description": "Request body larger than 32 KB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "504": {
            "description": "The backend did not respond in time.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v1/schemas": {
      "get": {
        "operationId": "getJsonSchemas",
        "tags": [
          "System"
        ],
        "summary": "Get the JSON Schema bundle",
        "description": "READ. Returns every request and response schema as a standalone JSON Schema Draft 2020-12 document (definitions under $defs). Identical to the components/schemas section of this specification and intended for code generation, automated testing and future MCP tool definitions.",
        "responses": {
          "200": {
            "description": "JSON Schema 2020-12 bundle.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "JSON Schema 2020-12 document with all definitions under $defs."
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": []
      }
    }
  },
  "components": {
    "securitySchemes": {},
    "schemas": {
      "HeroPath": {
        "type": "object",
        "title": "HeroPath",
        "description": "A VA Heroes PH career or training path (a program) exactly as published on the website.",
        "properties": {
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9-]{1,64}$",
            "minLength": 1,
            "maxLength": 64,
            "description": "URL slug identifying the path."
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "Display name."
          },
          "label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short badge label, null when the path has none."
          },
          "tagline": {
            "type": "string",
            "description": "One-line summary shown on the path card."
          },
          "description": {
            "type": "string",
            "description": "Short description used in listings."
          },
          "intro": {
            "type": "string",
            "description": "Longer introduction shown on the path page."
          },
          "highlights": {
            "type": "array",
            "description": "Key learning or role highlights.",
            "items": {
              "type": "string"
            }
          },
          "type": {
            "type": "string",
            "enum": [
              "training",
              "sales"
            ],
            "description": "\"training\" for VA training paths, \"sales\" for the Loan Officer career path."
          },
          "featured": {
            "type": "boolean",
            "description": "True for the highlighted starter path."
          },
          "externalUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "External program website, null when none exists."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canonical page URL on this website."
          }
        },
        "required": [
          "slug",
          "name",
          "label",
          "tagline",
          "description",
          "intro",
          "highlights",
          "type",
          "featured",
          "externalUrl",
          "url"
        ],
        "additionalProperties": false
      },
      "HeroPathList": {
        "type": "object",
        "title": "HeroPathList",
        "description": "A filtered collection of Hero Paths.",
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Items matching the filters."
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Items returned in this response."
          },
          "items": {
            "type": "array",
            "description": "The HeroPath records returned by this request.",
            "items": {
              "$ref": "#/components/schemas/HeroPath"
            }
          }
        },
        "required": [
          "total",
          "count",
          "items"
        ],
        "additionalProperties": false
      },
      "HeroStory": {
        "type": "object",
        "title": "HeroStory",
        "description": "A published testimonial. Contains no contact details or identifiers beyond the display name already shown on the website.",
        "properties": {
          "quote": {
            "type": "string",
            "description": "Testimonial text."
          },
          "name": {
            "type": "string",
            "description": "Display name as published."
          },
          "role": {
            "type": "string",
            "description": "Role or path the person follows."
          }
        },
        "required": [
          "quote",
          "name",
          "role"
        ],
        "additionalProperties": false
      },
      "HeroStoryList": {
        "type": "object",
        "title": "HeroStoryList",
        "description": "A collection of published Hero Stories.",
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Items matching the filters."
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Items returned in this response."
          },
          "items": {
            "type": "array",
            "description": "The HeroStory records returned by this request.",
            "items": {
              "$ref": "#/components/schemas/HeroStory"
            }
          }
        },
        "required": [
          "total",
          "count",
          "items"
        ],
        "additionalProperties": false
      },
      "ImpactStat": {
        "type": "object",
        "title": "ImpactStat",
        "description": "A published impact statistic.",
        "properties": {
          "label": {
            "type": "string",
            "description": "What the statistic measures."
          },
          "value": {
            "type": [
              "number",
              "null"
            ],
            "description": "Numeric value, null when the statistic is expressed as text."
          },
          "suffix": {
            "type": [
              "string",
              "null"
            ],
            "description": "Unit or suffix appended to the value, such as \"+\"."
          },
          "display": {
            "type": [
              "string",
              "null"
            ],
            "description": "Text shown instead of a number, when value is null."
          }
        },
        "required": [
          "label",
          "value",
          "suffix",
          "display"
        ],
        "additionalProperties": false
      },
      "ImpactStatList": {
        "type": "object",
        "title": "ImpactStatList",
        "description": "A collection of impact statistics.",
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Items matching the filters."
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Items returned in this response."
          },
          "items": {
            "type": "array",
            "description": "The ImpactStat records returned by this request.",
            "items": {
              "$ref": "#/components/schemas/ImpactStat"
            }
          }
        },
        "required": [
          "total",
          "count",
          "items"
        ],
        "additionalProperties": false
      },
      "Faq": {
        "type": "object",
        "title": "Faq",
        "description": "A published FAQ entry as shown on the About VA Heroes page.",
        "properties": {
          "id": {
            "type": "integer",
            "minimum": 1,
            "description": "Stable position-based identifier."
          },
          "question": {
            "type": "string",
            "description": "The question as published."
          },
          "answer": {
            "type": "string",
            "description": "The answer as published."
          }
        },
        "required": [
          "id",
          "question",
          "answer"
        ],
        "additionalProperties": false
      },
      "FaqList": {
        "type": "object",
        "title": "FaqList",
        "description": "A collection of published FAQ entries.",
        "properties": {
          "total": {
            "type": "integer",
            "minimum": 0,
            "description": "Items matching the filters."
          },
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Items returned in this response."
          },
          "items": {
            "type": "array",
            "description": "The Faq records returned by this request.",
            "items": {
              "$ref": "#/components/schemas/Faq"
            }
          }
        },
        "required": [
          "total",
          "count",
          "items"
        ],
        "additionalProperties": false
      },
      "SiteInfo": {
        "type": "object",
        "title": "SiteInfo",
        "description": "Public organization and website information. No private contact data is included.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Organization name."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Website home page."
          },
          "logoUrl": {
            "type": "string",
            "format": "uri",
            "description": "Public logo image URL."
          },
          "slogan": {
            "type": "string",
            "description": "Public slogan."
          },
          "description": {
            "type": "string",
            "description": "Public organization description."
          },
          "areaServed": {
            "type": "string",
            "description": "Primary area served."
          },
          "socialProfiles": {
            "type": "array",
            "description": "Public social profile URLs.",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "applicationUrl": {
            "type": "string",
            "format": "uri",
            "description": "Public page hosting the job application form."
          }
        },
        "required": [
          "name",
          "url",
          "logoUrl",
          "slogan",
          "description",
          "areaServed",
          "socialProfiles",
          "applicationUrl"
        ],
        "additionalProperties": false
      },
      "Health": {
        "type": "object",
        "title": "Health",
        "description": "API liveness information. With ?ready=true the response also reports readiness of the API and its database dependency, as booleans and status words only — never infrastructure details.",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded"
            ],
            "description": "\"ok\" when the service is healthy, \"degraded\" when a dependency is unavailable."
          },
          "service": {
            "type": "string",
            "description": "Service identifier."
          },
          "version": {
            "type": "string",
            "description": "API version identifier."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Server time of the response."
          },
          "ready": {
            "type": "boolean",
            "description": "Readiness result. Present only on the readiness probe."
          },
          "checks": {
            "type": "object",
            "description": "Dependency results. Present only on the readiness probe.",
            "properties": {
              "api": {
                "type": "string",
                "enum": [
                  "ok"
                ],
                "description": "Request pipeline is serving."
              },
              "database": {
                "type": "string",
                "enum": [
                  "ok",
                  "unavailable"
                ],
                "description": "Database reachability. No hostnames, credentials or error details."
              },
              "databaseLatencyMs": {
                "type": "integer",
                "minimum": 0,
                "description": "Round-trip duration of the database probe."
              }
            },
            "required": [
              "api",
              "database"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "status",
          "version",
          "timestamp"
        ],
        "additionalProperties": false
      },
      "ApplicationRequest": {
        "type": "object",
        "title": "ApplicationRequest",
        "description": "Fields accepted when submitting a job application. Unknown properties are rejected.",
        "properties": {
          "fullName": {
            "type": "string",
            "minLength": 2,
            "maxLength": 120,
            "description": "Applicant's full name."
          },
          "email": {
            "type": "string",
            "format": "email",
            "minLength": 3,
            "maxLength": 254,
            "description": "Contact email address."
          },
          "phone": {
            "type": "string",
            "minLength": 5,
            "maxLength": 32,
            "description": "Optional contact phone number."
          },
          "heroPathSlug": {
            "type": "string",
            "enum": [
              "general-va",
              "highlevel",
              "executive-assistant",
              "loan-processing",
              "bookkeeping-va",
              "shopify-va",
              "loan-officer"
            ],
            "description": "Optional slug of the Hero Path the applicant is interested in."
          },
          "message": {
            "type": "string",
            "maxLength": 2000,
            "description": "Optional message from the applicant."
          },
          "website": {
            "type": "string",
            "maxLength": 0,
            "description": "Anti-spam honeypot. Must be empty or omitted; any value rejects the request."
          }
        },
        "required": [
          "fullName",
          "email"
        ],
        "additionalProperties": false
      },
      "ContactRequest": {
        "type": "object",
        "title": "ContactRequest",
        "description": "Fields accepted when submitting a contact message. Unknown properties are rejected.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 120,
            "description": "Sender's name."
          },
          "email": {
            "type": "string",
            "format": "email",
            "minLength": 3,
            "maxLength": 254,
            "description": "Contact email address."
          },
          "subject": {
            "type": "string",
            "maxLength": 160,
            "description": "Optional subject line."
          },
          "message": {
            "type": "string",
            "minLength": 5,
            "maxLength": 2000,
            "description": "Message body."
          },
          "website": {
            "type": "string",
            "maxLength": 0,
            "description": "Anti-spam honeypot. Must be empty or omitted; any value rejects the request."
          }
        },
        "required": [
          "name",
          "email",
          "message"
        ],
        "additionalProperties": false
      },
      "SubmissionReceipt": {
        "type": "object",
        "title": "SubmissionReceipt",
        "description": "Confirmation that a submission was stored. Deliberately echoes none of the submitted personal data and exposes no internal database fields.",
        "properties": {
          "data": {
            "type": "object",
            "description": "Receipt for the stored submission. Never echoes the submitted content.",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid",
                "description": "Identifier of the stored submission."
              },
              "createdAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "When the submission was stored."
              },
              "status": {
                "type": "string",
                "enum": [
                  "received"
                ],
                "description": "Always \"received\"."
              },
              "duplicate": {
                "type": "boolean",
                "description": "True when an identical submission already existed; no new record was created."
              }
            },
            "required": [
              "id",
              "createdAt",
              "status",
              "duplicate"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "data"
        ],
        "additionalProperties": false
      },
      "ErrorResponse": {
        "type": "object",
        "title": "ErrorResponse",
        "description": "Uniform error envelope returned by every endpoint.",
        "properties": {
          "error": {
            "type": "object",
            "description": "The error envelope. Contains no internal, infrastructure or stack information.",
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "VALIDATION_ERROR",
                  "NOT_FOUND",
                  "METHOD_NOT_ALLOWED",
                  "PAYLOAD_TOO_LARGE",
                  "RATE_LIMITED",
                  "TIMEOUT",
                  "INTERNAL_ERROR"
                ],
                "description": "Machine-readable code."
              },
              "message": {
                "type": "string",
                "description": "Human-readable summary, safe to display."
              },
              "details": {
                "type": "object",
                "description": "Per-field validation messages or additional context. May be empty.",
                "additionalProperties": true
              },
              "requestId": {
                "type": "string",
                "description": "Correlation ID for this request, also returned in the x-request-id header. Quote it when reporting a failure; it exposes nothing internal."
              }
            },
            "required": [
              "code",
              "message",
              "details"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "HeroPathResponse": {
        "$ref": "#/components/schemas/HeroPath"
      },
      "HeroPathsResponse": {
        "$ref": "#/components/schemas/HeroPathList"
      },
      "HeroStoriesResponse": {
        "$ref": "#/components/schemas/HeroStoryList"
      },
      "ImpactStatsResponse": {
        "$ref": "#/components/schemas/ImpactStatList"
      },
      "FaqsResponse": {
        "$ref": "#/components/schemas/FaqList"
      },
      "SiteInfoResponse": {
        "$ref": "#/components/schemas/SiteInfo"
      },
      "HealthResponse": {
        "$ref": "#/components/schemas/Health"
      },
      "ApplicationResponse": {
        "$ref": "#/components/schemas/SubmissionReceipt"
      },
      "ContactResponse": {
        "$ref": "#/components/schemas/SubmissionReceipt"
      }
    },
    "responses": {
      "ValidationError": {
        "description": "One or more query parameters are invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "VALIDATION_ERROR",
                "message": "Invalid request",
                "details": {
                  "limit": "Must be an integer between 1 and 100."
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested resource does not exist.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "NOT_FOUND",
                "message": "Hero Path not found",
                "details": {
                  "slug": "unknown-path"
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "INTERNAL_ERROR",
                "message": "Unexpected server error",
                "details": {}
              }
            }
          }
        }
      },
      "UnprocessableEntity": {
        "description": "The request body failed server-side validation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "VALIDATION_ERROR",
                "message": "The request contains invalid data.",
                "details": {
                  "email": "Must be a valid email address."
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many submissions from this client.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": {
                "code": "RATE_LIMITED",
                "message": "Too many submissions. Please try again later.",
                "details": {
                  "retryAfterSeconds": 600
                }
              }
            }
          }
        }
      }
    }
  },
  "security": []
}
