{"openapi":"3.1.0","info":{"title":"Secani OSCAL Validation API","version":"1.0.0","description":"Validate OSCAL 1.2.2 JSON documents over HTTP. POST the document itself as the request body — no envelope, no account.\n\nPrivacy contract: documents are processed in memory in the EU (Vercel fra1) and discarded when the response is sent. Nothing is persisted or logged beyond aggregate metrics (model type, size bucket, outcome, duration).\n\nLimits: 4 MB raw request body, 24 MB decompressed (send Content-Encoding: gzip for large artifacts — OSCAL JSON compresses well). Anonymous rate limits: 10 requests/minute and 300/day per client, surfaced via RateLimit-* headers. With an API key (Authorization: Bearer sk_oscal_…, created in the organization settings): 120 requests/minute and 10,000/day per key, enforced durably.\n\nValidation depth: level=schema (default) runs JSON Schema validation; level=full additionally runs the semantic (OSCAL constraint) layer. rules= (comma-separated semantic rule ids) opts extra, default-off rules into a full run and is only valid with level=full. oscal-version pins the spec version (only \"1.2.2\").\n\nA full run reports meta.semanticRules = { count, sha256 }: the number of active semantic rule ids and a stable SHA-256 over that sorted id set, so a result records exactly which rules were checked."},"externalDocs":{"description":"Secani OSCAL Validation API documentation","url":"https://secani.com/docs/oscal/api"},"servers":[{"url":"https://secani.com"}],"tags":[{"name":"OSCAL validation","description":"Public, stateless validation of OSCAL 1.2.2 JSON documents."},{"name":"Discovery","description":"Machine-readable API discovery documents."}],"paths":{"/api/oscal/v1":{"get":{"operationId":"getOscalApiIndex","summary":"Discover the Secani OSCAL API","description":"Returns canonical links, authentication behavior, and the published endpoint for the public Secani OSCAL Validation API.","tags":["Discovery"],"security":[],"responses":{"200":{"description":"The public API index and canonical documentation links.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIndex"}}}}}}},"/api/oscal/v1/validate":{"post":{"operationId":"validateOscalDocument","summary":"Validate an OSCAL 1.2.2 JSON document","description":"Validates one OSCAL 1.2.2 JSON document in memory and returns a typed report. Anonymous requests are supported; a single-purpose Secani OSCAL API key only raises validation rate limits and does not grant workspace access.","tags":["OSCAL validation"],"security":[{},{"bearerApiKey":[]}],"parameters":[{"name":"level","in":"query","required":false,"schema":{"type":"string","enum":["schema","full"],"default":"schema"},"description":"Validation depth. \"schema\" (default) runs JSON Schema validation; \"full\" adds the semantic (OSCAL constraint) layer."},{"name":"rules","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated semantic rule ids to enable on top of the default-enabled set. Only valid with level=full; unknown ids are rejected."},{"name":"oscal-version","in":"query","required":false,"schema":{"type":"string","enum":["1.2.2"]},"description":"OSCAL specification version pin. Only \"1.2.2\" in v1."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OscalDocument"}}}},"responses":{"200":{"description":"Validation completed. valid:false is a successful validation of an invalid document — branch on the field, not the status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationReport"}}}},"400":{"$ref":"#/components/responses/Problem"},"401":{"$ref":"#/components/responses/Problem"},"413":{"$ref":"#/components/responses/Problem"},"415":{"$ref":"#/components/responses/Problem"},"429":{"$ref":"#/components/responses/Problem"},"500":{"$ref":"#/components/responses/Problem"},"503":{"$ref":"#/components/responses/Problem"}}}},"/api/oscal/v1/openapi.json":{"get":{"operationId":"getVersionedOpenApiDocument","summary":"Get the versioned OpenAPI document","description":"Returns the same OpenAPI 3.1 contract as the canonical /openapi.json discovery URL.","tags":["Discovery"],"security":[],"responses":{"200":{"description":"The OpenAPI 3.1 description of this API.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/openapi.json":{"get":{"operationId":"getCanonicalOpenApiDocument","summary":"Get the canonical OpenAPI document","description":"Returns the canonical OpenAPI 3.1 description of the public Secani OSCAL Validation API.","tags":["Discovery"],"security":[],"responses":{"200":{"description":"The canonical OpenAPI 3.1 description of this API.","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"securitySchemes":{"bearerApiKey":{"type":"http","scheme":"bearer","description":"Organization API key in the sk_oscal_… format, created in the organization settings and shown exactly once. Optional: anonymous requests stay valid at lower rate limits."}},"responses":{"Problem":{"description":"RFC 9457 problem details with a stable machine-readable `code`.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}},"schemas":{"OscalDocument":{"description":"One complete OSCAL 1.2.2 JSON document. Exactly one supported root model identifies the document type.","oneOf":[{"type":"object","required":["catalog"],"properties":{"catalog":{"type":"object","description":"The OSCAL catalog model content."}},"additionalProperties":false},{"type":"object","required":["profile"],"properties":{"profile":{"type":"object","description":"The OSCAL profile model content."}},"additionalProperties":false},{"type":"object","required":["component-definition"],"properties":{"component-definition":{"type":"object","description":"The OSCAL component-definition model content."}},"additionalProperties":false},{"type":"object","required":["system-security-plan"],"properties":{"system-security-plan":{"type":"object","description":"The OSCAL system-security-plan model content."}},"additionalProperties":false},{"type":"object","required":["assessment-plan"],"properties":{"assessment-plan":{"type":"object","description":"The OSCAL assessment-plan model content."}},"additionalProperties":false},{"type":"object","required":["assessment-results"],"properties":{"assessment-results":{"type":"object","description":"The OSCAL assessment-results model content."}},"additionalProperties":false},{"type":"object","required":["plan-of-action-and-milestones"],"properties":{"plan-of-action-and-milestones":{"type":"object","description":"The OSCAL plan-of-action-and-milestones model content."}},"additionalProperties":false},{"type":"object","required":["mapping-collection"],"properties":{"mapping-collection":{"type":"object","description":"The OSCAL mapping-collection model content."}},"additionalProperties":false}]},"ApiIndex":{"type":"object","required":["name","version","description","documentation","openapi","permissions","errors","endpoints","authentication"],"properties":{"name":{"type":"string"},"version":{"type":"string","const":"v1"},"description":{"type":"string"},"documentation":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"},"permissions":{"type":"string","format":"uri"},"errors":{"type":"string","format":"uri"},"endpoints":{"type":"object","required":["validate"],"properties":{"validate":{"type":"object","required":["method","url","contentType"],"properties":{"method":{"type":"string","const":"POST"},"url":{"type":"string","format":"uri"},"contentType":{"type":"string","const":"application/json"}}}}},"authentication":{"type":"object","required":["anonymous","optionalApiKey"],"properties":{"anonymous":{"type":"boolean","const":true},"optionalApiKey":{"type":"object","required":["scheme","prefix","purpose","grantsWorkspaceAccess"],"properties":{"scheme":{"type":"string","const":"Bearer"},"prefix":{"type":"string","const":"sk_oscal_"},"purpose":{"type":"string"},"grantsWorkspaceAccess":{"type":"boolean","const":false}}}}}}},"ValidationIssue":{"type":"object","required":["ruleId","path","message","keyword","severity"],"properties":{"ruleId":{"type":"string","description":"Stable id of the rule that produced the finding (schema-derived or semantic, e.g. \"CAT-002.a\")."},"path":{"type":"string","description":"RFC 6901 JSON Pointer into the submitted document."},"message":{"type":"string"},"keyword":{"type":"string","description":"JSON Schema keyword or constraint that failed (required, type, …)."},"severity":{"type":"string","enum":["error","warning"]}}},"ValidationReport":{"type":"object","required":["valid","model","oscalVersion","level","complete","issues","issueCount","truncated","meta"],"properties":{"valid":{"type":"boolean"},"model":{"type":"string","enum":["catalog","profile","component-definition","system-security-plan","assessment-plan","assessment-results","plan-of-action-and-milestones","mapping-collection"]},"oscalVersion":{"type":"string","description":"The oscal-version the document declares in its metadata; \"unknown\" when absent."},"level":{"type":"string","enum":["schema","full"],"description":"The validation depth that ran (echoes the request)."},"complete":{"type":"boolean","description":"Whether every requested layer ran to completion for a recognized model and version."},"issues":{"type":"array","items":{"$ref":"#/components/schemas/ValidationIssue"},"description":"At most 200 issues; issueCount carries the true total."},"issueCount":{"type":"integer"},"truncated":{"type":"boolean"},"meta":{"type":"object","required":["engine","validator","schemaSource","patches","durationMs"],"properties":{"engine":{"type":"string"},"validator":{"type":"string","description":"The OSCAL release the precompiled validators target (e.g. \"1.2.2\")."},"schemaSource":{"type":"string"},"patches":{"type":"array","items":{"type":"string"},"description":"Documented deviations from the raw NIST release schemas."},"durationMs":{"type":"integer"},"semanticRules":{"type":"object","required":["count","sha256"],"description":"Present only on level=full runs: the active semantic rule-id set as a reproducibility identifier.","properties":{"count":{"type":"integer","description":"Number of semantic rule ids that were active."},"sha256":{"type":"string","description":"SHA-256 (hex) over the sorted active rule-id set."}}}}}}},"Problem":{"type":"object","required":["type","title","status","code","resolution","documentation"],"properties":{"type":{"type":"string","format":"uri"},"title":{"type":"string"},"status":{"type":"integer"},"code":{"type":"string","enum":["ERR_INVALID_JSON","ERR_INVALID_UTF8","ERR_UNKNOWN_MODEL","ERR_INVALID_CONTENT_ENCODING","ERR_UNSUPPORTED_PARAMETER","ERR_METHOD_NOT_ALLOWED","ERR_NOT_FOUND","ERR_PAYLOAD_TOO_LARGE","ERR_UNSUPPORTED_MEDIA_TYPE","ERR_RATE_LIMITED","ERR_INVALID_API_KEY","ERR_KEY_SERVICE_UNAVAILABLE","ERR_INTERNAL"]},"detail":{"type":"string"},"resolution":{"type":"string","description":"A safe, actionable next step for resolving the error."},"documentation":{"type":"string","format":"uri"}}}}}}