{
  "openapi": "3.1.0",
  "info": {
    "title": "Sidekick Pro API",
    "version": "1.0.0",
    "summary": "Public and agent-facing HTTP surface of Sidekick Pro.",
    "description": "Sidekick Pro is an AI executive assistant for solo operators and small businesses.\n\nThis description covers the endpoints an external agent or integrator can call: the MCP server at `/mcp`, its OAuth 2.1 authorization endpoints, and the public catalog and health endpoints. The product's own first-party app endpoints are authenticated with session cookies and are not part of this contract.\n\nAgents should start at `GET /.well-known/oauth-protected-resource`, which is the machine-readable entry point for the MCP server.\n\nAuthorization is delegated in full — see the `sidekickOAuth` security scheme.\n\nHuman-readable documentation lives at https://sidekickpro.com/developers. A Markdown index of the whole site for LLM consumption lives at https://sidekickpro.com/llms.txt.",
    "termsOfService": "https://sidekickpro.com/terms-of-service",
    "contact": {
      "name": "Sidekick Pro",
      "url": "https://sidekickpro.com/developers",
      "email": "hello@sidekickpro.com"
    }
  },
  "servers": [
    {
      "url": "https://sidekickpro.com",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Sidekick Pro developer documentation",
    "url": "https://sidekickpro.com/developers"
  },
  "tags": [
    {
      "name": "MCP",
      "description": "Model Context Protocol server. Gives an agent one tool, `messageSidekick`."
    },
    {
      "name": "OAuth",
      "description": "OAuth 2.1 authorization for the MCP server. Scoped, with PKCE and dynamic client registration."
    },
    {
      "name": "Catalog",
      "description": "Public, unauthenticated product catalog."
    },
    {
      "name": "Status",
      "description": "Service health."
    }
  ],
  "components": {
    "securitySchemes": {
      "sidekickOAuth": {
        "type": "oauth2",
        "description": "OAuth 2.1 authorization code flow with PKCE (S256) and RFC 7591 dynamic client registration. The server issues a single scope, `mcp:tools`, which grants an agent the same assistant access the signed-in user has. Authorization is delegated in full: there is currently no narrower scope to request.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://sidekickpro.com/mcp/oauth/authorize",
            "tokenUrl": "https://sidekickpro.com/mcp/oauth/token",
            "refreshUrl": "https://sidekickpro.com/mcp/oauth/token",
            "scopes": {
              "mcp:tools": "Full assistant access. Sidekick may use every tool it has and act on the user's behalf — email, calendar, phone, SMS, documents, browser control, and connected apps. This is the only scope the server issues."
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "error_description": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      },
      "ProtectedResourceMetadata": {
        "type": "object",
        "description": "RFC 9728 protected resource metadata.",
        "properties": {
          "resource": {
            "type": "string",
            "format": "uri"
          },
          "authorization_servers": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "bearer_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "AuthorizationServerMetadata": {
        "type": "object",
        "description": "RFC 8414 authorization server metadata.",
        "properties": {
          "issuer": {
            "type": "string",
            "format": "uri"
          },
          "authorization_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "token_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "registration_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "response_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "grant_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "token_endpoint_auth_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "code_challenge_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "const": "Bearer"
          },
          "expires_in": {
            "type": "integer"
          },
          "refresh_token": {
            "type": "string"
          },
          "scope": {
            "type": "string",
            "description": "The scope granted, space separated. Currently always `mcp:tools`."
          }
        },
        "required": [
          "access_token",
          "token_type",
          "scope"
        ]
      }
    }
  },
  "paths": {
    "/.well-known/oauth-protected-resource": {
      "get": {
        "tags": [
          "OAuth"
        ],
        "summary": "Protected resource metadata for the MCP server",
        "description": "RFC 9728. The discovery entry point: it names the authorization server and the scopes this resource understands.",
        "security": [],
        "responses": {
          "200": {
            "description": "Resource metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedResourceMetadata"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "tags": [
          "OAuth"
        ],
        "summary": "Authorization server metadata",
        "description": "RFC 8414. Lists the authorize, token and registration endpoints, the supported grants, and `scopes_supported`.",
        "security": [],
        "responses": {
          "200": {
            "description": "Authorization server metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationServerMetadata"
                }
              }
            }
          }
        }
      }
    },
    "/mcp/oauth/register": {
      "post": {
        "tags": [
          "OAuth"
        ],
        "summary": "Dynamic client registration",
        "description": "RFC 7591. Register a client and receive a `client_id` and `client_secret`.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "redirect_uris": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uri"
                    },
                    "minItems": 1
                  },
                  "client_name": {
                    "type": "string"
                  }
                },
                "required": [
                  "redirect_uris"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Client registered"
          },
          "400": {
            "description": "redirect_uris missing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/mcp/oauth/authorize": {
      "get": {
        "tags": [
          "OAuth"
        ],
        "summary": "Authorization endpoint",
        "description": "Authorization code flow with PKCE. The user is shown which client is asking and what it will be able to do, and approves explicitly.",
        "security": [],
        "parameters": [
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "const": "code"
            }
          },
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "schema": {
              "type": "string",
              "const": "S256"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "description": "Space-separated scopes. `mcp:tools` is the only scope issued, and it is granted whether or not this parameter is present.",
            "schema": {
              "type": "string",
              "examples": [
                "mcp:tools"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Consent page (HTML)",
            "content": {
              "text/html": {}
            }
          },
          "302": {
            "description": "Redirect to the client's redirect_uri with an authorization code, or to sign-in when the user has no session"
          },
          "400": {
            "description": "invalid_request or unsupported_response_type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/mcp/oauth/token": {
      "post": {
        "tags": [
          "OAuth"
        ],
        "summary": "Token endpoint",
        "description": "Exchanges an authorization code for tokens, or rotates a refresh token. The response states the scope granted, which is always `mcp:tools`.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "authorization_code",
                      "refresh_token"
                    ]
                  },
                  "code": {
                    "type": "string"
                  },
                  "redirect_uri": {
                    "type": "string",
                    "format": "uri"
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "code_verifier": {
                    "type": "string"
                  },
                  "refresh_token": {
                    "type": "string"
                  }
                },
                "required": [
                  "grant_type"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tokens issued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request, invalid_grant, or unsupported_grant_type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "MCP server (Streamable HTTP transport)",
        "description": "Model Context Protocol endpoint. Exposes one tool, `messageSidekick`, which takes a natural-language message for the user's assistant and returns its reply.\n\nAuthorization is all-or-nothing: a valid bearer token carries `mcp:tools` and reaches the assistant with every tool enabled. Treat a token for this endpoint as equivalent to the user's own access.",
        "security": [
          {
            "sidekickOAuth": [
              "mcp:tools"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "description": "A JSON-RPC 2.0 message as defined by the Model Context Protocol.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "No valid bearer token. The `WWW-Authenticate` header names the resource metadata URL and the scope to request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/billing/plan-cards": {
      "get": {
        "tags": [
          "Catalog"
        ],
        "summary": "Public plan catalog",
        "description": "The pricing-card copy for each plan, merged with live monthly and yearly prices. Unauthenticated and safe to cache.",
        "security": [],
        "responses": {
          "200": {
            "description": "Plan cards",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/healthcheck": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Service health",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "const": "ok"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
