{
  "openapi": "3.1.0",
  "info": {
    "title": "RaftLabs Website API",
    "version": "1.0.0",
    "summary": "The public HTTP surface of raftlabs.com: a service health check. Site content is published for agents as HTML, Markdown and plain text rather than through an API.",
    "description": "RaftLabs is a software product agency building web, mobile, and AI applications.\n\nThis document describes the endpoints intended for third-party and agent\nuse. Other first-party routes exist to serve specific pages on the site and\nare not part of the supported surface — do not call them.\n\nThere is no API for contacting RaftLabs or requesting a quote. To reach a\nhuman, use the form at https://www.raftlabs.com/contact-us or email team@raftlabs.com. Agent\ntask guides live at https://www.raftlabs.com/.well-known/agent-skills/index.json.\n\nSite content itself is static HTML and is additionally published for agents\nas Markdown and plain text — see /llms.txt, /llms-full.txt, /pricing.md, and\nthe RFC 9727 catalog at /.well-known/api-catalog.\n\nEvery error response uses RFC 9457 problem details (`application/problem+json`)\nwith two extension members: `code` (stable machine identifier) and `hint`\n(what to change before retrying).\n\nVersioning: the major version is in the URL path. /api/v1 is\ncurrent and every response carries `API-Version: 1`. A\nbreaking change ships under a new prefix, never on an existing one. The full\npolicy, including how a retirement is signalled and the minimum notice\nperiod, is machine-readable under `x-api-lifecycle` and written out at https://www.raftlabs.com/developers.\n\nRate limits: every response carries `RateLimit-Limit`, `RateLimit-Remaining`,\n`RateLimit-Reset`, `RateLimit-Policy` and `RateLimit`, on success as well as\non refusal, so a client can pace itself before it is throttled. A 429 adds\n`Retry-After`. Quotas are counted per serverless instance and per client IP,\nso the reported budget is a floor rather than a global guarantee.",
    "contact": {
      "name": "RaftLabs",
      "email": "team@raftlabs.com",
      "url": "https://www.raftlabs.com/contact-us"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://www.raftlabs.com/terms-of-service"
    }
  },
  "servers": [
    {
      "url": "https://www.raftlabs.com",
      "description": "Production"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Developer portal: quickstart, versioning policy and rate limits",
    "url": "https://www.raftlabs.com/developers"
  },
  "tags": [
    {
      "name": "status",
      "description": "Service availability."
    }
  ],
  "x-api-lifecycle": {
    "versioning": {
      "scheme": "url-path-major",
      "current": "1",
      "pathPrefix": "/api/v1",
      "responseHeader": "API-Version",
      "supported": [
        "1"
      ],
      "unversionedAliases": [
        {
          "path": "/api/health",
          "aliasOf": "/api/v1/health",
          "note": "Permanent alias of the current version. Not deprecated."
        }
      ],
      "breakingChanges": [
        "Removing an endpoint, or removing a field from a response.",
        "Renaming a field, or changing its type.",
        "Adding a required request field, or tightening validation on an existing one.",
        "Changing the HTTP status or the `code` returned for an existing condition."
      ],
      "nonBreakingChanges": [
        "Adding an endpoint.",
        "Adding an optional request field.",
        "Adding a field to a response — parse defensively and ignore what you do not use.",
        "Adding a new `code` value for a condition that previously had none."
      ]
    },
    "deprecation": {
      "minimumNoticeDays": 180,
      "signals": [
        "`Deprecation` response header (RFC 9745) carrying the date the deprecation took effect, as a structured-field date: `Deprecation: @1780272000`.",
        "`Sunset` response header (RFC 8594) carrying the date the endpoint stops answering, as an HTTP-date.",
        "`Link` response header with `rel=\"successor-version\"` pointing at the replacement.",
        "`deprecated: true` on the operation in /openapi.json, with the successor named in its description.",
        "An entry in the deprecations table on /developers, listing the sunset date."
      ],
      "active": [],
      "policyUrl": "https://www.raftlabs.com/developers"
    },
    "rateLimits": {
      "headers": [
        "RateLimit-Limit",
        "RateLimit-Remaining",
        "RateLimit-Reset",
        "RateLimit-Policy",
        "RateLimit",
        "Retry-After"
      ],
      "enforcement": "per-instance",
      "note": "Quotas are counted per serverless instance and per client IP, so the reported budget is a floor rather than a global guarantee. Treat 429 as authoritative and honour `Retry-After`.",
      "documentationUrl": "https://www.raftlabs.com/developers"
    }
  },
  "paths": {
    "/api/v1/health": {
      "get": {
        "operationId": "getHealthV1",
        "tags": [
          "status"
        ],
        "summary": "Service health",
        "description": "Confirms the site is reachable. This is the canonical, versioned path. Requires no authentication. Reports reachability only — no dependency values are returned.",
        "responses": {
          "200": {
            "description": "Service is reachable.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                },
                "example": {
                  "status": "ok",
                  "service": "raftlabs-website",
                  "version": "1"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed` — Method not allowed. Retry with one of the HTTP methods in the `Allow` response header.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limit_exceeded` — Rate limit exceeded. Wait before retrying, or contact team@raftlabs.com for a higher allowance.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "getHealth",
        "tags": [
          "status"
        ],
        "summary": "Service health",
        "description": "Confirms the site is reachable. Permanent unversioned alias of /api/v1/health, kept because /.well-known/api-catalog, /llms.txt and external monitors already reference it. Not deprecated; it always mirrors the current version. Requires no authentication. Reports reachability only — no dependency values are returned.",
        "responses": {
          "200": {
            "description": "Service is reachable.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                },
                "example": {
                  "status": "ok",
                  "service": "raftlabs-website",
                  "version": "1"
                }
              }
            }
          },
          "405": {
            "description": "`method_not_allowed` — Method not allowed. Retry with one of the HTTP methods in the `Allow` response header.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limit_exceeded` — Rate limit exceeded. Wait before retrying, or contact team@raftlabs.com for a higher allowance.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "API-Version": {
                "$ref": "#/components/headers/API-Version"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "title": "Problem",
        "description": "RFC 9457 problem details. `code` and `hint` are RaftLabs extension members; `error` and `message` are flat aliases of `code` and `detail` kept for existing browser clients.",
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "code",
          "hint"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "Problem type URI, anchored at this document.",
            "examples": [
              "https://www.raftlabs.com/openapi.json#invalid_request_body"
            ]
          },
          "title": {
            "type": "string",
            "description": "Stable summary of the problem type."
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation of this occurrence."
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code.",
            "enum": [
              "invalid_request_body",
              "missing_required_field",
              "captcha_verification_failed",
              "not_found",
              "method_not_allowed",
              "rate_limit_exceeded",
              "server_misconfigured",
              "upstream_error",
              "internal_error"
            ]
          },
          "hint": {
            "type": "string",
            "description": "What to change before retrying."
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          },
          "error": {
            "type": "string",
            "description": "Alias of `code`."
          },
          "message": {
            "type": "string",
            "description": "Alias of `detail`."
          }
        }
      },
      "Health": {
        "type": "object",
        "required": [
          "status",
          "service",
          "version"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok"
            ]
          },
          "service": {
            "type": "string",
            "examples": [
              "raftlabs-website"
            ]
          },
          "version": {
            "type": "string",
            "description": "Major API version that served the response.",
            "examples": [
              "1"
            ]
          }
        }
      }
    },
    "headers": {
      "RateLimit-Limit": {
        "description": "Requests permitted in the current window. Draft-03 discrete form of the IETF rate-limit headers. Example: 120.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Remaining": {
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Reset": {
        "description": "Seconds until the current window resets.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Policy": {
        "description": "Structured field naming the policy, its quota and its window. Example: \"health\";q=120;w=60.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit": {
        "description": "Structured field carrying the live budget. Example: \"health\";r=119;t=60.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before retrying. Sent only with a 429, where RFC 9110 gives it meaning.",
        "schema": {
          "type": "integer"
        }
      },
      "API-Version": {
        "description": "Major API version that served the response.",
        "schema": {
          "type": "string",
          "examples": [
            "1"
          ]
        }
      }
    }
  }
}