{
  "openapi": "3.1.0",
  "info": {
    "title": "Evergreen Comply Public API",
    "version": "1.0.0",
    "summary": "Read-only discovery API for Evergreen Comply training courses",
    "description": "Discover Evergreen Comply's public online compliance-training catalog and published pricing. No authentication is required. Purchases, learner data, certificates, account records, and seat assignments are not available through this API.",
    "contact": {
      "name": "Evergreen Comply customer service",
      "url": "https://www.evergreencomply.com/contact",
      "email": "support@evergreencomply.com"
    },
    "license": {
      "name": "Evergreen Comply API Terms",
      "url": "https://www.evergreencomply.com/terms-of-service"
    }
  },
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "servers": [
    {
      "url": "https://www.evergreencomply.com",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Evergreen Comply developer documentation",
    "url": "https://www.evergreencomply.com/developers"
  },
  "tags": [
    {
      "name": "Courses",
      "description": "Read-only access to courses intentionally offered in Evergreen Comply's public sales catalog"
    }
  ],
  "paths": {
    "/api/public/v1/courses": {
      "get": {
        "operationId": "listPublicCourses",
        "summary": "List public training courses",
        "description": "Returns public sales-catalog courses with structured price, duration, audience, regulation, language, and canonical URL fields. Filters are optional and can be combined.",
        "tags": ["Courses"],
        "parameters": [
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Return courses offered in this language.",
            "schema": {
              "type": "string",
              "enum": ["English", "Spanish"]
            },
            "example": "Spanish"
          },
          {
            "name": "regulation",
            "in": "query",
            "required": false,
            "description": "Case-insensitive text to match against the course regulation.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            },
            "example": "DOT"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of matching courses to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 100
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "The current public course catalog.",
            "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/CourseCollectionResponse"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" },
          "default": { "$ref": "#/components/responses/Problem" }
        }
      }
    },
    "/api/public/v1/courses/{courseId}": {
      "get": {
        "operationId": "getPublicCourse",
        "summary": "Get one public training course",
        "description": "Returns one public course by the stable course ID emitted by listPublicCourses. Use the returned canonical URL for complete scope and purchasing information.",
        "tags": ["Courses"],
        "parameters": [
          {
            "name": "courseId",
            "in": "path",
            "required": true,
            "description": "Stable course identifier from the public catalog.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 120,
              "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
            },
            "example": "dot-hazmat-general"
          }
        ],
        "responses": {
          "200": {
            "description": "The requested public course.",
            "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/CourseResponse" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" },
          "default": { "$ref": "#/components/responses/Problem" }
        }
      }
    }
  },
  "components": {
    "headers": {
      "ApiVersion": {
        "description": "Major API version that produced the response.",
        "schema": { "type": "string", "const": "1" }
      },
      "RateLimit": {
        "description": "Current quota name, remaining requests, and seconds until reset.",
        "schema": {
          "type": "string",
          "example": "\"anonymous\";r=119;t=60"
        }
      },
      "RateLimitPolicy": {
        "description": "Quota policy: 120 requests per 60-second window.",
        "schema": {
          "type": "string",
          "example": "\"anonymous\";q=120;w=60"
        }
      }
    },
    "schemas": {
      "Money": {
        "type": "object",
        "additionalProperties": false,
        "required": ["amount", "currency", "unit"],
        "properties": {
          "amount": {
            "type": "number",
            "minimum": 0,
            "description": "Price in major currency units."
          },
          "currency": { "type": "string", "const": "USD" },
          "unit": { "type": "string", "const": "seat" }
        }
      },
      "Course": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "title",
          "url",
          "price",
          "duration",
          "audience",
          "regulation",
          "languages"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable public course identifier."
          },
          "title": { "type": "string" },
          "url": { "type": "string", "format": "uri" },
          "price": { "$ref": "#/components/schemas/Money" },
          "duration": { "type": "string" },
          "audience": { "type": "string" },
          "regulation": { "type": "string" },
          "languages": {
            "type": "array",
            "minItems": 1,
            "items": { "type": "string" }
          }
        }
      },
      "CourseCollectionResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["data", "meta"],
        "properties": {
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Course" }
          },
          "meta": {
            "type": "object",
            "additionalProperties": false,
            "required": ["count", "total"],
            "properties": {
              "count": { "type": "integer", "minimum": 0 },
              "total": { "type": "integer", "minimum": 0 }
            }
          }
        }
      },
      "CourseResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["data"],
        "properties": {
          "data": { "$ref": "#/components/schemas/Course" }
        }
      },
      "ProblemDetails": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "code",
          "resolution",
          "docs_url"
        ],
        "properties": {
          "type": { "type": "string", "format": "uri-reference" },
          "title": { "type": "string" },
          "status": { "type": "integer", "minimum": 400, "maximum": 599 },
          "detail": { "type": "string" },
          "instance": { "type": "string", "format": "uri-reference" },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code."
          },
          "resolution": {
            "type": "string",
            "description": "Concrete next step an agent can take."
          },
          "docs_url": { "type": "string", "format": "uri" }
        }
      }
    },
    "responses": {
      "Problem": {
        "description": "The request could not be completed. Inspect code and resolution before retrying.",
        "headers": {
          "API-Version": { "$ref": "#/components/headers/ApiVersion" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      },
      "BadRequest": {
        "description": "A query parameter is invalid.",
        "headers": {
          "API-Version": { "$ref": "#/components/headers/ApiVersion" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      },
      "NotFound": {
        "description": "The requested course does not exist in the public catalog.",
        "headers": {
          "API-Version": { "$ref": "#/components/headers/ApiVersion" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      },
      "RateLimited": {
        "description": "The client exceeded 120 requests in 60 seconds.",
        "headers": {
          "API-Version": { "$ref": "#/components/headers/ApiVersion" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "Retry-After": {
            "description": "Seconds to wait before retrying.",
            "schema": { "type": "integer", "minimum": 1 }
          }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      },
      "ServerError": {
        "description": "The API could not complete the request.",
        "headers": {
          "API-Version": { "$ref": "#/components/headers/ApiVersion" },
          "RateLimit": { "$ref": "#/components/headers/RateLimit" },
          "RateLimit-Policy": { "$ref": "#/components/headers/RateLimitPolicy" }
        },
        "content": {
          "application/problem+json": {
            "schema": { "$ref": "#/components/schemas/ProblemDetails" }
          }
        }
      }
    }
  }
}
