{
  "openapi": "3.1.0",
  "info": {
    "title": "HypeApps Playground API",
    "version": "1.0.0",
    "summary": "Publish and read HAM (Hypermedia Application Markup) snippets.",
    "description": "The public HTTP API behind the HypeApps playground at https://hypeapps.dev/playground. It lets you publish a HAM snippet and get back a short share code, update that snippet with the edit token you were issued, and read any snippet as rendered markup or as JSON. HAM is the HTML-like markup HypeApps renders into a native mobile app; the full markup reference is at https://hypeapps.dev/llms.txt. This API is read/write for snippets only — there is no account system, and HypeApps itself is pre-launch.",
    "contact": {
      "name": "HypeApps",
      "url": "https://hypeapps.dev/developers",
      "email": "laz@communityfluency.com"
    },
    "license": {
      "name": "Proprietary — all rights reserved",
      "url": "https://hypeapps.dev/privacy"
    }
  },
  "servers": [
    { "url": "https://hypeapps.dev", "description": "Production" }
  ],
  "externalDocs": {
    "description": "HAM markup reference and product docs (llms.txt)",
    "url": "https://hypeapps.dev/llms.txt"
  },
  "tags": [
    { "name": "Snippets", "description": "Create, update, and read HAM snippets." }
  ],
  "paths": {
    "/p": {
      "post": {
        "tags": ["Snippets"],
        "operationId": "createSnippet",
        "summary": "Publish a HAM snippet",
        "description": "Publishes a HAM document and returns a short share code (the slug), a canonical URL, and an edit token. Store the edit token: it is the only credential that can later update this snippet, and it is returned exactly once. No authentication is required to create a snippet.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SnippetInput" },
              "example": { "ham": "<app>\n  <config primary_color=\"teal\"></config>\n  <screen>\n    <app-bar title=\"Hello\"/>\n    <main><box style=\"p-24\"><h2 style=\"font-bold\">Hello 👋</h2></box></main>\n  </screen>\n</app>\n" }
            },
            "application/x-www-form-urlencoded": {
              "schema": { "$ref": "#/components/schemas/SnippetInput" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Snippet created.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SnippetCreated" },
                "example": { "slug": "7m3ef", "url": "https://hypeapps.dev/p/7m3ef", "edit_token": "N0tARealToken000000000000000000000000000" }
              }
            }
          },
          "422": {
            "description": "Validation failed (missing or oversized `ham`).",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationError" } } }
          }
        }
      }
    },
    "/p/{slug}": {
      "parameters": [
        { "$ref": "#/components/parameters/Slug" }
      ],
      "get": {
        "tags": ["Snippets"],
        "operationId": "getSnippetMarkup",
        "summary": "Get a snippet as rendered HAM markup",
        "description": "Returns the raw HAM markup for a snippet as `text/html`. This is the representation the HypeApps native client fetches and renders. For a machine-readable envelope, use `GET /p/{slug}.json` instead.",
        "responses": {
          "200": {
            "description": "The HAM markup.",
            "content": { "text/html": { "schema": { "type": "string" }, "example": "<app>…</app>" } }
          },
          "404": {
            "description": "No snippet with that slug.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      },
      "put": {
        "tags": ["Snippets"],
        "operationId": "updateSnippet",
        "summary": "Update a snippet",
        "description": "Replaces the HAM for an existing snippet. Requires the `edit_token` issued when the snippet was created. A snippet keeps one slug for life; updating never mints a new code.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SnippetUpdate" },
              "example": { "ham": "<app>…updated…</app>", "edit_token": "N0tARealToken000000000000000000000000000" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Snippet updated.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SnippetRef" }, "example": { "slug": "7m3ef", "url": "https://hypeapps.dev/p/7m3ef" } } }
          },
          "403": {
            "description": "Wrong or missing edit token.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "404": {
            "description": "No snippet with that slug.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "422": {
            "description": "Validation failed.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationError" } } }
          }
        }
      }
    },
    "/p/{slug}.json": {
      "parameters": [
        { "$ref": "#/components/parameters/Slug" }
      ],
      "get": {
        "tags": ["Snippets"],
        "operationId": "getSnippetJson",
        "summary": "Get a snippet as JSON",
        "description": "Returns a snippet as a JSON envelope containing its slug and its HAM source — the representation to fetch when you want to read the markup programmatically.",
        "responses": {
          "200": {
            "description": "The snippet envelope.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SnippetJson" }, "example": { "slug": "hello", "ham": "<app>…</app>" } } }
          },
          "404": {
            "description": "No snippet with that slug.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Slug": {
        "name": "slug",
        "in": "path",
        "required": true,
        "description": "The share code for a snippet: 4–16 lowercase letters and digits. Generated codes avoid ambiguous characters (0, 1, i, l, o).",
        "schema": { "type": "string", "pattern": "^[a-z0-9]{4,16}$", "examples": ["7m3ef", "hello"] }
      }
    },
    "schemas": {
      "SnippetInput": {
        "type": "object",
        "required": ["ham"],
        "properties": {
          "ham": {
            "type": "string",
            "maxLength": 200000,
            "description": "The HAM markup to publish. See https://hypeapps.dev/llms.txt for the tag and attribute reference."
          }
        }
      },
      "SnippetUpdate": {
        "type": "object",
        "required": ["ham", "edit_token"],
        "properties": {
          "ham": { "type": "string", "maxLength": 200000, "description": "The replacement HAM markup." },
          "edit_token": { "type": "string", "description": "The token returned by createSnippet. Authorizes the update." }
        }
      },
      "SnippetCreated": {
        "type": "object",
        "required": ["slug", "url", "edit_token"],
        "properties": {
          "slug": { "type": "string", "description": "The share code for the new snippet." },
          "url": { "type": "string", "format": "uri", "description": "Canonical URL of the snippet." },
          "edit_token": { "type": "string", "description": "Credential for future updates. Returned once — store it." }
        }
      },
      "SnippetRef": {
        "type": "object",
        "required": ["slug", "url"],
        "properties": {
          "slug": { "type": "string" },
          "url": { "type": "string", "format": "uri" }
        }
      },
      "SnippetJson": {
        "type": "object",
        "required": ["slug", "ham"],
        "properties": {
          "slug": { "type": "string" },
          "ham": { "type": "string", "description": "The snippet's HAM source." }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "object",
            "required": ["code", "status", "message"],
            "properties": {
              "code": { "type": "string", "description": "Stable machine-readable error code.", "examples": ["not_found"] },
              "status": { "type": "integer", "description": "HTTP status code.", "examples": [404] },
              "message": { "type": "string", "description": "Human-readable explanation." },
              "hint": { "type": "string", "description": "How to resolve or where to look next." },
              "documentation": { "type": "string", "format": "uri", "description": "Link to relevant docs." }
            }
          }
        }
      },
      "ValidationError": {
        "type": "object",
        "required": ["message", "errors"],
        "properties": {
          "message": { "type": "string" },
          "errors": {
            "type": "object",
            "additionalProperties": { "type": "array", "items": { "type": "string" } },
            "description": "Field name to array of validation messages."
          }
        }
      }
    }
  }
}
