{
  "openapi": "3.0.3",
  "info": {
    "title": "Aircover Public Agent API",
    "version": "1.0.0",
    "description": "The public, agent-facing API surface of Aircover — the AI-powered real-time sales coaching and enablement platform. This specification covers the OAuth 2.0 authorization endpoints and the Model Context Protocol (MCP) endpoint that AI agents use to access Aircover on behalf of an authenticated user. Aircover's full REST API is available to customers; contact support@aircover.ai for access. New users receive a free trial license automatically on self-serve sign-up.",
    "contact": {
      "name": "Aircover Support",
      "email": "support@aircover.ai",
      "url": "https://www.aircover.ai/developers"
    },
    "termsOfService": "https://www.aircover.ai/terms-and-conditions"
  },
  "externalDocs": {
    "description": "Aircover Developer & Agent Resources",
    "url": "https://www.aircover.ai/developers"
  },
  "servers": [
    {
      "url": "https://api.aircover.ai",
      "description": "Production"
    }
  ],
  "security": [
    {
      "oauth2": ["mcp"]
    }
  ],
  "tags": [
    {
      "name": "mcp",
      "description": "Model Context Protocol server (Streamable HTTP transport)"
    },
    {
      "name": "oauth",
      "description": "OAuth 2.0 authorization server (authorization code + PKCE, dynamic client registration)"
    },
    {
      "name": "discovery",
      "description": "Machine-readable discovery metadata"
    }
  ],
  "paths": {
    "/mcp": {
      "post": {
        "operationId": "mcpJsonRpc",
        "tags": ["mcp"],
        "summary": "MCP JSON-RPC endpoint",
        "description": "Model Context Protocol endpoint over Streamable HTTP. Send JSON-RPC 2.0 messages (initialize, tools/list, tools/call, …). Available tools: list_meetings, get_meeting, get_meeting_transcript, ask_documents, list_agents, agent_results, get_qualification_results, get_deals, get_deal, get_teams, list_reports, read_report. All data access is bounded by the authenticated user's organization permissions. Unauthenticated requests receive 401 with a WWW-Authenticate header pointing at the protected-resource metadata; MCP clients complete the OAuth flow automatically.",
        "security": [{"oauth2": ["mcp"]}],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/JsonRpcRequest"}
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC 2.0 response",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/JsonRpcResponse"}
              }
            }
          },
          "401": {
            "description": "Missing or invalid access token. The WWW-Authenticate header references the protected resource metadata at /.well-known/oauth-protected-resource."
          }
        }
      }
    },
    "/oauth/authorize": {
      "get": {
        "operationId": "oauthAuthorize",
        "tags": ["oauth"],
        "summary": "OAuth 2.0 authorization endpoint",
        "description": "Begin the authorization code flow. PKCE (S256) is required. The user signs in with their Aircover account (Google, Microsoft, or enterprise OIDC SSO) and consents to the requested scopes, then is redirected to redirect_uri with an authorization code.",
        "security": [],
        "parameters": [
          {"name": "response_type", "in": "query", "required": true, "schema": {"type": "string", "enum": ["code"]}, "description": "Must be 'code'."},
          {"name": "client_id", "in": "query", "required": true, "schema": {"type": "string"}, "description": "Client identifier from dynamic client registration."},
          {"name": "redirect_uri", "in": "query", "required": true, "schema": {"type": "string", "format": "uri"}, "description": "Registered redirect URI."},
          {"name": "scope", "in": "query", "required": false, "schema": {"type": "string", "example": "mcp"}, "description": "Space-separated scopes. See the 'oauth2' security scheme for available scopes."},
          {"name": "state", "in": "query", "required": false, "schema": {"type": "string"}, "description": "Opaque value echoed back on redirect for CSRF protection."},
          {"name": "code_challenge", "in": "query", "required": true, "schema": {"type": "string"}, "description": "PKCE code challenge."},
          {"name": "code_challenge_method", "in": "query", "required": true, "schema": {"type": "string", "enum": ["S256"]}, "description": "PKCE challenge method; only S256 is supported."}
        ],
        "responses": {
          "302": {
            "description": "Redirect to the sign-in flow, then back to redirect_uri with ?code=…&state=… on success or ?error=… on failure."
          },
          "400": {
            "description": "Invalid request (unknown client_id, bad redirect_uri, missing PKCE)."
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "operationId": "oauthToken",
        "tags": ["oauth"],
        "summary": "OAuth 2.0 token endpoint",
        "description": "Exchange an authorization code (with PKCE code_verifier) for an access token, or refresh an access token. Client authentication via client_secret_basic or client_secret_post.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {"$ref": "#/components/schemas/TokenRequest"}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/TokenResponse"}
              }
            }
          },
          "400": {
            "description": "OAuth 2.0 error response (invalid_grant, invalid_client, …)",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/OAuthError"}
              }
            }
          }
        }
      }
    },
    "/oauth/register": {
      "post": {
        "operationId": "oauthRegisterClient",
        "tags": ["oauth"],
        "summary": "Dynamic client registration (RFC 7591)",
        "description": "Register an OAuth client programmatically — no manual key issuance. MCP clients use this to onboard without human intervention beyond user consent.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/ClientRegistrationRequest"}
            }
          }
        },
        "responses": {
          "201": {
            "description": "Client registered",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/ClientRegistrationResponse"}
              }
            }
          },
          "400": {
            "description": "Invalid client metadata",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/OAuthError"}
              }
            }
          }
        }
      }
    },
    "/oauth/revoke": {
      "post": {
        "operationId": "oauthRevokeToken",
        "tags": ["oauth"],
        "summary": "Token revocation (RFC 7009)",
        "description": "Revoke an access or refresh token.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": ["token"],
                "properties": {
                  "token": {"type": "string", "description": "The token to revoke."},
                  "token_type_hint": {"type": "string", "enum": ["access_token", "refresh_token"], "description": "Optional hint about the token type."}
                }
              }
            }
          }
        },
        "responses": {
          "200": {"description": "Token revoked (or was already invalid)."}
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "operationId": "getAuthorizationServerMetadata",
        "tags": ["discovery"],
        "summary": "Authorization server metadata (RFC 8414)",
        "description": "Machine-readable OAuth 2.0 authorization server metadata: endpoints, supported scopes, grant types, and PKCE methods. Also reachable via redirect from www.aircover.ai/.well-known/oauth-authorization-server.",
        "security": [],
        "responses": {
          "200": {
            "description": "Authorization server metadata",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/AuthorizationServerMetadata"}
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "operationId": "getProtectedResourceMetadata",
        "tags": ["discovery"],
        "summary": "Protected resource metadata (RFC 9728)",
        "description": "Identifies the MCP endpoint as an OAuth 2.0 protected resource and names its authorization server.",
        "security": [],
        "responses": {
          "200": {
            "description": "Protected resource metadata",
            "content": {
              "application/json": {
                "schema": {"$ref": "#/components/schemas/ProtectedResourceMetadata"}
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 authorization code flow with PKCE (S256) and dynamic client registration. Scopes are granted per-client and always bounded by the authenticated user's own organization permissions — an agent can never see more than the user who authorized it.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.aircover.ai/oauth/authorize",
            "tokenUrl": "https://api.aircover.ai/oauth/token",
            "refreshUrl": "https://api.aircover.ai/oauth/token",
            "scopes": {
              "mcp": "Access the MCP tool surface: meetings, transcripts, AI agent results, deal qualification, reports, teams, and indexed documents — read-scoped to the authorizing user's organization role."
            }
          }
        }
      }
    },
    "schemas": {
      "JsonRpcRequest": {
        "type": "object",
        "required": ["jsonrpc", "method"],
        "properties": {
          "jsonrpc": {"type": "string", "enum": ["2.0"]},
          "id": {"description": "Request id (string or number). Omit for notifications.", "oneOf": [{"type": "string"}, {"type": "integer"}]},
          "method": {"type": "string", "description": "MCP method, e.g. initialize, tools/list, tools/call.", "example": "tools/list"},
          "params": {"type": "object", "description": "Method parameters. For tools/call: {\"name\": \"list_meetings\", \"arguments\": {…}}.", "additionalProperties": true}
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": ["jsonrpc"],
        "properties": {
          "jsonrpc": {"type": "string", "enum": ["2.0"]},
          "id": {"oneOf": [{"type": "string"}, {"type": "integer"}]},
          "result": {"type": "object", "description": "Present on success.", "additionalProperties": true},
          "error": {"$ref": "#/components/schemas/JsonRpcError"}
        }
      },
      "JsonRpcError": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": {"type": "integer", "description": "JSON-RPC error code."},
          "message": {"type": "string"},
          "data": {"description": "Optional error details."}
        }
      },
      "TokenRequest": {
        "type": "object",
        "required": ["grant_type"],
        "properties": {
          "grant_type": {"type": "string", "enum": ["authorization_code", "refresh_token"]},
          "code": {"type": "string", "description": "Authorization code (grant_type=authorization_code)."},
          "redirect_uri": {"type": "string", "format": "uri", "description": "Must match the authorization request."},
          "code_verifier": {"type": "string", "description": "PKCE code verifier."},
          "refresh_token": {"type": "string", "description": "Refresh token (grant_type=refresh_token)."},
          "client_id": {"type": "string", "description": "Required with client_secret_post authentication."},
          "client_secret": {"type": "string", "description": "Required with client_secret_post authentication."}
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": ["access_token", "token_type"],
        "properties": {
          "access_token": {"type": "string"},
          "token_type": {"type": "string", "example": "Bearer"},
          "expires_in": {"type": "integer", "description": "Access token lifetime in seconds."},
          "refresh_token": {"type": "string"},
          "scope": {"type": "string", "example": "mcp"}
        }
      },
      "OAuthError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {"type": "string", "example": "invalid_grant"},
          "error_description": {"type": "string"}
        }
      },
      "ClientRegistrationRequest": {
        "type": "object",
        "required": ["redirect_uris"],
        "properties": {
          "client_name": {"type": "string", "description": "Human-readable client name shown on the consent screen."},
          "redirect_uris": {"type": "array", "items": {"type": "string", "format": "uri"}, "minItems": 1},
          "grant_types": {"type": "array", "items": {"type": "string", "enum": ["authorization_code", "refresh_token"]}},
          "response_types": {"type": "array", "items": {"type": "string", "enum": ["code"]}},
          "token_endpoint_auth_method": {"type": "string", "enum": ["client_secret_basic", "client_secret_post"]},
          "scope": {"type": "string", "example": "mcp"}
        }
      },
      "ClientRegistrationResponse": {
        "type": "object",
        "required": ["client_id"],
        "properties": {
          "client_id": {"type": "string"},
          "client_secret": {"type": "string", "description": "Returned once at registration; store securely."},
          "client_name": {"type": "string"},
          "redirect_uris": {"type": "array", "items": {"type": "string", "format": "uri"}},
          "grant_types": {"type": "array", "items": {"type": "string"}},
          "response_types": {"type": "array", "items": {"type": "string"}},
          "token_endpoint_auth_method": {"type": "string"},
          "scope": {"type": "string"}
        }
      },
      "AuthorizationServerMetadata": {
        "type": "object",
        "required": ["issuer", "authorization_endpoint", "token_endpoint"],
        "properties": {
          "issuer": {"type": "string", "format": "uri", "example": "https://api.aircover.ai"},
          "authorization_endpoint": {"type": "string", "format": "uri"},
          "token_endpoint": {"type": "string", "format": "uri"},
          "registration_endpoint": {"type": "string", "format": "uri"},
          "revocation_endpoint": {"type": "string", "format": "uri"},
          "scopes_supported": {"type": "array", "items": {"type": "string"}, "example": ["mcp"]},
          "response_types_supported": {"type": "array", "items": {"type": "string"}},
          "grant_types_supported": {"type": "array", "items": {"type": "string"}},
          "code_challenge_methods_supported": {"type": "array", "items": {"type": "string"}},
          "token_endpoint_auth_methods_supported": {"type": "array", "items": {"type": "string"}}
        }
      },
      "ProtectedResourceMetadata": {
        "type": "object",
        "required": ["resource", "authorization_servers"],
        "properties": {
          "resource": {"type": "string", "format": "uri", "example": "https://api.aircover.ai/mcp"},
          "authorization_servers": {"type": "array", "items": {"type": "string", "format": "uri"}}
        }
      }
    }
  }
}
