{
  "openapi": "3.1.0",
  "info": {
    "title": "Layerr public API",
    "summary": "Marketing MCP, machine discovery, and product OAuth scopes",
    "description": "Layerr public machine surface on this origin. POST /mcp is an unauthenticated, read-only Streamable HTTP MCP for site markdown. Product Explore tools live at mcp.layerr.ai and require OAuth with a scoped token. There is no self-serve API key and no sandbox.",
    "version": "1.0.0",
    "contact": {
      "name": "Layerr",
      "email": "hello@layerr.ai",
      "url": "https://layerr.ai/contact"
    },
    "license": {
      "name": "Site notice",
      "url": "https://layerr.ai/privacy"
    }
  },
  "servers": [
    {
      "url": "/",
      "description": "This origin — public marketing API and discovery"
    },
    {
      "url": "https://mcp.layerr.ai",
      "description": "Authenticated product MCP (OAuth required)"
    }
  ],
  "tags": [
    {
      "name": "mcp",
      "description": "Public marketing MCP (no auth)"
    },
    {
      "name": "discovery",
      "description": "OpenAPI, well-known, llms.txt, health"
    },
    {
      "name": "product",
      "description": "Authenticated product MCP at mcp.layerr.ai"
    }
  ],
  "paths": {
    "/mcp": {
      "get": {
        "operationId": "getMarketingMcpBrief",
        "tags": [
          "mcp"
        ],
        "summary": "Marketing MCP markdown brief",
        "description": "Tells agents this URL is Streamable HTTP. Use POST for JSON-RPC initialize, then get_overview or when_to_use.",
        "responses": {
          "200": {
            "description": "Markdown brief",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "postMarketingMcpJsonRpc",
        "tags": [
          "mcp"
        ],
        "summary": "Marketing MCP JSON-RPC",
        "description": "Unauthenticated Streamable HTTP. Methods: initialize, tools/list, tools/call, resources/list, resources/read. No contact-form tool and no customer data.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "id": {
                    "description": "Request id; omit for notifications"
                  },
                  "method": {
                    "type": "string",
                    "description": "initialize, ping, tools/list, tools/call, resources/list, resources/read, notifications/initialized"
                  },
                  "params": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "initialize",
                "params": {
                  "protocolVersion": "2025-03-26",
                  "capabilities": {},
                  "clientInfo": {
                    "name": "agent",
                    "version": "0"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result or error object",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "429": {
            "description": "Per-IP POST cap",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message",
                        "resolution"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine code (not_found, rate_limited, …)"
                        },
                        "message": {
                          "type": "string",
                          "description": "What failed"
                        },
                        "resolution": {
                          "type": "string",
                          "description": "Where to look next"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "options": {
        "operationId": "optionsMarketingMcp",
        "tags": [
          "mcp"
        ],
        "summary": "CORS preflight for the marketing MCP",
        "description": "Allows POST from any origin with content-type and MCP protocol headers.",
        "responses": {
          "204": {
            "description": "CORS headers only"
          }
        }
      }
    },
    "/.well-known/mcp": {
      "get": {
        "operationId": "getMcpWellKnown",
        "tags": [
          "mcp",
          "discovery"
        ],
        "summary": "MCP discovery document",
        "description": "JSON catalog for the public marketing MCP: endpoint, version, serverUrl, tools, resources. POST this same path to run the live initialize handshake.",
        "responses": {
          "200": {
            "description": "Discovery JSON",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "postMcpWellKnownHandshake",
        "tags": [
          "mcp"
        ],
        "summary": "Live MCP handshake at the well-known URL",
        "description": "Same JSON-RPC router as POST /mcp. Use initialize here when a client discovered the server via /.well-known/mcp.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "id": {
                    "description": "Request id; omit for notifications"
                  },
                  "method": {
                    "type": "string",
                    "description": "initialize, ping, tools/list, tools/call, resources/list, resources/read, notifications/initialized"
                  },
                  "params": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/mcp/server-card.json": {
      "get": {
        "operationId": "getMcpServerCard",
        "tags": [
          "mcp",
          "discovery"
        ],
        "summary": "MCP server card",
        "description": "Same body as /.well-known/mcp, including version and serverUrl.",
        "responses": {
          "200": {
            "description": "Server card JSON",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api.json": {
      "get": {
        "operationId": "getPublicApiCatalog",
        "tags": [
          "discovery"
        ],
        "summary": "Layerr public API catalog",
        "description": "JSON index of OpenAPI, MCP, OAuth metadata, and docs. Unknown /api/* paths return structured JSON errors (code, message, resolution).",
        "responses": {
          "200": {
            "description": "Catalog JSON",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiJson",
        "tags": [
          "discovery"
        ],
        "summary": "Layerr OpenAPI specification (JSON)",
        "description": "This document. Unique operationId and description on every operation.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 JSON",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api/openapi.yaml": {
      "get": {
        "operationId": "getOpenApiYaml",
        "tags": [
          "discovery"
        ],
        "summary": "Layerr OpenAPI specification (YAML)",
        "description": "Same spec as /openapi.json. Body is JSON, which is valid YAML 1.2.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 as YAML-compatible JSON",
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.yaml": {
      "get": {
        "operationId": "getOpenApiYamlRoot",
        "tags": [
          "discovery"
        ],
        "summary": "Layerr OpenAPI specification (YAML, root)",
        "description": "Same spec as /openapi.json. Body is JSON, which is valid YAML 1.2.",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 as YAML-compatible JSON",
            "content": {
              "application/yaml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/healthz": {
      "get": {
        "operationId": "getHealthz",
        "tags": [
          "discovery"
        ],
        "summary": "Liveness probe",
        "description": "Railway and agents: JSON { ok, service } when the process is up.",
        "responses": {
          "200": {
            "description": "Alive",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "service"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "service": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/readyz": {
      "get": {
        "operationId": "getReadyz",
        "tags": [
          "discovery"
        ],
        "summary": "Readiness probe",
        "description": "Same shape as /healthz. Static site — ready when the server boots.",
        "responses": {
          "200": {
            "description": "Ready",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "service"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "service": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "tags": [
          "discovery"
        ],
        "summary": "Agent navigation index",
        "description": "What Layerr is, when to use it, and links to MCP, OpenAPI, auth, and problem pages.",
        "responses": {
          "200": {
            "description": "Plain-text / markdown index",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "operationId": "getOauthAuthorizationServer",
        "tags": [
          "discovery",
          "product"
        ],
        "summary": "OAuth 2.0 authorization-server metadata",
        "description": "RFC 8414 document for the product authorization server. Issuer is mcp.layerr.ai. Marketing MCP does not use these tokens.",
        "responses": {
          "200": {
            "description": "AS metadata including scopes_supported",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/openid-configuration": {
      "get": {
        "operationId": "getOpenIdConfiguration",
        "tags": [
          "discovery",
          "product"
        ],
        "summary": "OpenID Connect discovery",
        "description": "Same product issuer as the OAuth metadata, plus claims_supported.",
        "responses": {
          "200": {
            "description": "OIDC metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "operationId": "getOauthProtectedResource",
        "tags": [
          "discovery",
          "product"
        ],
        "summary": "Protected-resource metadata for the product MCP",
        "description": "Names the product MCP resource, authorization server, and MCP scopes.",
        "responses": {
          "200": {
            "description": "Resource metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp/user/{userId}": {
      "servers": [
        {
          "url": "https://mcp.layerr.ai"
        }
      ],
      "post": {
        "operationId": "postProductMcpJsonRpc",
        "tags": [
          "product"
        ],
        "summary": "Product MCP JSON-RPC (OAuth)",
        "description": "Authenticated Explore tools for a Layerr user the caller can already reach. Requires a scoped OAuth token from the product authorization server. This is not the public marketing catalog at POST /mcp.",
        "security": [
          {
            "oauth2": [
              "mcp:tools:read",
              "mcp:tools:invoke"
            ]
          }
        ],
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "Layerr user id that owns the product MCP session",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "id": {
                    "description": "Request id; omit for notifications"
                  },
                  "method": {
                    "type": "string",
                    "description": "initialize, ping, tools/list, tools/call, resources/list, resources/read, notifications/initialized"
                  },
                  "params": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message",
                        "resolution"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine code (not_found, rate_limited, …)"
                        },
                        "message": {
                          "type": "string",
                          "description": "What failed"
                        },
                        "resolution": {
                          "type": "string",
                          "description": "Where to look next"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No resource at this path.",
                    "resolution": "Read https://layerr.ai/openapi.json or https://layerr.ai/llms.txt. Public API is POST https://layerr.ai/mcp. Auth: https://layerr.ai/auth."
                  }
                }
              }
            }
          },
          "403": {
            "description": "Token is valid but missing the required scope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message",
                        "resolution"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine code (not_found, rate_limited, …)"
                        },
                        "message": {
                          "type": "string",
                          "description": "What failed"
                        },
                        "resolution": {
                          "type": "string",
                          "description": "Where to look next"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "JsonError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "resolution"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine code (not_found, rate_limited, …)"
              },
              "message": {
                "type": "string",
                "description": "What failed"
              },
              "resolution": {
                "type": "string",
                "description": "Where to look next"
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "Product MCP OAuth. Request only the scopes the job needs. Marketing MCP at POST /mcp does not use this scheme.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://mcp.layerr.ai/oauth2/authorize",
            "tokenUrl": "https://mcp.layerr.ai/oauth2/token",
            "refreshUrl": "https://mcp.layerr.ai/oauth2/token",
            "scopes": {
              "openid": "OpenID Connect identity",
              "profile": "Display name on the authenticated principal",
              "email": "Email on the authenticated principal",
              "offline_access": "Refresh token for long-lived agent sessions",
              "mcp:tools:read": "List tools the caller can already reach on the product MCP",
              "mcp:tools:invoke": "Invoke those product MCP tools",
              "mcp:explore:read": "Read governed Explore catalogs the caller can already reach",
              "mcp:explore:query": "Run governed Explore queries the caller can already reach"
            }
          }
        }
      }
    }
  }
}
