{
  "openapi": "3.1.0",
  "info": {
    "title": "Serverless Framework — serverless.com",
    "version": "1.0.0",
    "summary": "Machine-readable surface of serverless.com (content endpoints and the public read-only content API) and the Serverless Platform License Keys API.",
    "description": "Public content and metadata endpoints served by serverless.com, a public read-only JSON content API under `/api/v1`, and the Serverless Platform License Keys management API on core.serverless.com.\n\n## Versioning and deprecation policy\n\nThe content API is versioned in the URL path (`/api/v1/...`). Breaking changes ship only as a new path version (`/api/v2/...`); existing versions keep working during a deprecation window of at least 90 days, signaled with `Deprecation` and `Sunset` response headers and announced on the blog (https://www.serverless.com/blog). Additive changes (new fields, new endpoints) may appear within a version without notice.\n\n## Rate limits\n\n`/api/v1` endpoints allow 120 requests per client per 60-second window, advertised on every response via the IETF `RateLimit-Policy` and `RateLimit` structured fields (plus the legacy `RateLimit-Limit`/`RateLimit-Remaining`/`RateLimit-Reset` triple). 429 responses include `Retry-After`.\n\n## Errors\n\nEvery `/api/*` error is an RFC 9457 `application/problem+json` document with a stable `code`, a human-readable `detail`, and a `resolution` hint. Unknown API routes return such a 404 — never an HTML error page.\n\n## Authentication\n\nThe serverless.com endpoints in this spec are public and need no authentication. The Platform API uses scoped API key roles rather than a single all-powerful credential:\n\n- **Access Keys** (`serverlessAccessKey`): bearer tokens scoped to a single organization, created in the Dashboard under Settings > Access Keys. Required for the Platform API endpoints in this spec.\n- **License Keys**: a lower-privilege credential role for CLI license validation only. License Keys cannot access the Dashboard or Platform API — they disable Dashboard access entirely — so agents that only need to run the Serverless Framework CLI should use a License Key instead of an Access Key. See https://www.serverless.com/framework/docs/guides/license-keys.",
    "contact": {
      "name": "Serverless Inc.",
      "url": "https://www.serverless.com/contact",
      "email": "support@serverless.com"
    },
    "termsOfService": "https://www.serverless.com/legal/terms"
  },
  "externalDocs": {
    "description": "Serverless Framework documentation",
    "url": "https://www.serverless.com/framework/docs"
  },
  "servers": [
    {
      "url": "https://www.serverless.com",
      "description": "serverless.com website"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getHomepage",
        "summary": "Homepage",
        "description": "Serverless Framework product overview. This URL supports content negotiation: browsers get `text/html`, agents sending `Accept: text/markdown` (or requesting the `.md` sibling URL) get `text/markdown`. Responses carry `Vary: Accept`.",
        "security": [],
        "responses": {
          "200": {
            "description": "The page, as HTML or markdown depending on the Accept header.",
            "headers": {
              "Vary": {
                "description": "Always includes Accept.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Unknown path. The markdown variant includes links to the sitemap, llms.txt, and docs index for recovery.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "406": {
            "description": "The Accept header rejects both text/html and text/markdown.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/framework/docs/{path}": {
      "get": {
        "operationId": "getDocumentationPage",
        "summary": "Documentation page",
        "description": "A Serverless Framework documentation page (e.g. `getting-started`, `providers/aws/guide/serverless.yml`). This URL supports content negotiation: browsers get `text/html`, agents sending `Accept: text/markdown` (or requesting the `.md` sibling URL) get `text/markdown`. Responses carry `Vary: Accept`.",
        "security": [],
        "responses": {
          "200": {
            "description": "The page, as HTML or markdown depending on the Accept header.",
            "headers": {
              "Vary": {
                "description": "Always includes Accept.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Unknown path. The markdown variant includes links to the sitemap, llms.txt, and docs index for recovery.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "406": {
            "description": "The Accept header rejects both text/html and text/markdown.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "Documentation path; may contain multiple segments. The full list of pages is in /sitemap.xml and /llms.txt.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/blog/{slug}": {
      "get": {
        "operationId": "getBlogPostPage",
        "summary": "Blog post",
        "description": "A Serverless blog post. This URL supports content negotiation: browsers get `text/html`, agents sending `Accept: text/markdown` (or requesting the `.md` sibling URL) get `text/markdown`. Responses carry `Vary: Accept`.",
        "security": [],
        "responses": {
          "200": {
            "description": "The page, as HTML or markdown depending on the Accept header.",
            "headers": {
              "Vary": {
                "description": "Always includes Accept.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Unknown path. The markdown variant includes links to the sitemap, llms.txt, and docs index for recovery.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "406": {
            "description": "The Accept header rejects both text/html and text/markdown.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Blog post slug (list via GET /api/v1/blog/posts).",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "summary": "Agent-friendly site index",
        "description": "llmstxt.org-format index of the most important pages on this site.",
        "security": [],
        "responses": {
          "200": {
            "description": "Agent-friendly site index",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiSpec",
        "summary": "This OpenAPI specification",
        "description": "The OpenAPI 3.1 description of the public endpoints.",
        "security": [],
        "responses": {
          "200": {
            "description": "This OpenAPI specification",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "summary": "Sitemap",
        "description": "XML sitemap of all indexed URLs.",
        "security": [],
        "responses": {
          "200": {
            "description": "Sitemap",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/robots.txt": {
      "get": {
        "operationId": "getRobotsTxt",
        "summary": "Robots policy",
        "description": "Crawler policy; also points at the sitemap.",
        "security": [],
        "responses": {
          "200": {
            "description": "Robots policy",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/blog/rss.xml": {
      "get": {
        "operationId": "getBlogRssFeed",
        "summary": "Blog RSS feed",
        "description": "RSS feed of the latest Serverless blog posts.",
        "security": [],
        "responses": {
          "200": {
            "description": "Blog RSS feed",
            "content": {
              "application/rss+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/blog/posts": {
      "get": {
        "operationId": "listBlogPosts",
        "summary": "List blog posts",
        "description": "Paginated list of Serverless blog posts, newest first, with links to each post’s HTML and markdown representations.",
        "security": [],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1-100. Defaults to 20.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List blog posts",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlogPost"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit or offset parameter.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Wait `Retry-After` seconds, then retry; honor the RateLimit headers to self-throttle.",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/blog/posts/{slug}": {
      "get": {
        "operationId": "getBlogPost",
        "summary": "Get a blog post",
        "description": "Metadata for one blog post, with links to its HTML and markdown representations.",
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Blog post slug (list via GET /api/v1/blog/posts).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The blog post.",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data"
                  ],
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/BlogPost"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No blog post exists with this slug.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Wait `Retry-After` seconds, then retry; honor the RateLimit headers to self-throttle.",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/plugins": {
      "get": {
        "operationId": "listPlugins",
        "summary": "List plugins",
        "description": "Paginated directory of Serverless Framework plugins.",
        "security": [],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1-100. Defaults to 20.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List plugins",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Plugin"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit or offset parameter.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Wait `Retry-After` seconds, then retry; honor the RateLimit headers to self-throttle.",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/examples": {
      "get": {
        "operationId": "listExamples",
        "summary": "List examples",
        "description": "Paginated directory of Serverless Framework example projects.",
        "security": [],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1-100. Defaults to 20.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List examples",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Example"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit or offset parameter.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Wait `Retry-After` seconds, then retry; honor the RateLimit headers to self-throttle.",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/guides": {
      "get": {
        "operationId": "listGuides",
        "summary": "List guides",
        "description": "The list of long-form serverless guides.",
        "security": [],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size, 1-100. Defaults to 20.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of items to skip. Defaults to 0.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List guides",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "pagination"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Guide"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit or offset parameter.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Wait `Retry-After` seconds, then retry; honor the RateLimit headers to self-throttle.",
            "headers": {
              "RateLimit-Policy": {
                "description": "IETF rate-limit policy structured field: `\"public-content\";q=120;w=60` (120 requests per client per 60s window).",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit": {
                "description": "IETF rate-limit structured field with remaining quota (`r`) and seconds until reset (`t`).",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/accesskeys/{orgId}": {
      "servers": [
        {
          "url": "https://core.serverless.com",
          "description": "Serverless Platform API"
        }
      ],
      "parameters": [
        {
          "name": "orgId",
          "in": "path",
          "required": true,
          "description": "Your organization ID, found in the Dashboard under Settings > General.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "listLicenseKeys",
        "summary": "List License Keys",
        "description": "Lists the License Keys for an organization. Requires an org-scoped Access Key.",
        "security": [
          {
            "serverlessAccessKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The organization’s License Keys.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LicenseKey"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Access Key."
          }
        }
      },
      "post": {
        "operationId": "createLicenseKey",
        "summary": "Create a License Key",
        "description": "Creates a License Key for an organization. Requires an org-scoped Access Key.",
        "security": [
          {
            "serverlessAccessKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "label"
                ],
                "properties": {
                  "label": {
                    "type": "string",
                    "description": "Human-readable label for the new key."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created License Key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/LicenseKey"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid Access Key."
          }
        }
      },
      "delete": {
        "operationId": "deleteLicenseKey",
        "summary": "Delete a License Key",
        "description": "Deletes a License Key from an organization. Requires an org-scoped Access Key.",
        "security": [
          {
            "serverlessAccessKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "label",
                  "key"
                ],
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "key": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Deleted. No response body is returned."
          },
          "401": {
            "description": "Missing or invalid Access Key."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. Every /api/* error response uses this shape with Content-Type application/problem+json.",
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "code"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri",
            "description": "URI identifying the error type."
          },
          "title": {
            "type": "string",
            "description": "Short error summary."
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable explanation of this occurrence."
          },
          "instance": {
            "type": "string",
            "description": "The request path that produced the error."
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code."
          },
          "resolution": {
            "type": "string",
            "description": "Hint for how to recover."
          },
          "documentation_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": [
          "total",
          "limit",
          "offset",
          "hasMore"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total items available."
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether more items exist beyond this page."
          }
        }
      },
      "BlogPost": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "url",
          "markdown_url"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "date": {
            "type": [
              "string",
              "null"
            ],
            "description": "Publication date (ISO 8601)."
          },
          "authors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTML representation."
          },
          "markdown_url": {
            "type": "string",
            "format": "uri",
            "description": "Markdown representation."
          }
        }
      },
      "Plugin": {
        "type": "object",
        "required": [
          "name",
          "title",
          "url"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "npm package name."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": [
              "string",
              "null"
            ]
          },
          "github_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "author": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Example": {
        "type": "object",
        "required": [
          "name",
          "title",
          "url"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "language": {
            "type": [
              "string",
              "null"
            ]
          },
          "platform": {
            "type": [
              "string",
              "null"
            ]
          },
          "framework_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "github_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Guide": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "url",
          "markdown_url"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "markdown_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "LicenseKey": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The license key material."
          },
          "label": {
            "type": "string",
            "description": "Human-readable label."
          },
          "orgId": {
            "type": "string"
          },
          "subscriptionId": {
            "type": "string"
          },
          "version": {
            "type": "string",
            "examples": [
              "V2"
            ]
          },
          "createdAt": {
            "type": "integer",
            "description": "Creation time (Unix epoch milliseconds)."
          },
          "updatedAt": {
            "type": "integer",
            "description": "Last update time (Unix epoch milliseconds)."
          }
        }
      }
    },
    "securitySchemes": {
      "serverlessAccessKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Serverless Dashboard Access Key, scoped to a single organization. Create one in the Dashboard under Settings > Access Keys (https://app.serverless.com/settings/accessKeys). Grants programmatic access to that organization’s Platform API resources only. For CLI-only license validation, use the lower-privilege License Key role instead of an Access Key (see https://www.serverless.com/framework/docs/guides/license-keys)."
      }
    }
  }
}