{
  "openapi": "3.0.3",
  "info": {
    "title": "3Dogs Nexus Decision Intelligence API",
    "version": "1.0.0",
    "description": "Public API for 3Dogs Nexus \u2014 adversarial multi-model decision intelligence. Submit a high-stakes business decision; a panel of 10-40+ AI models researches, debates, and returns a decisive recommendation with preserved dissent as a PDF report. Authentication is session-cookie based (create a session via /api/login). New accounts receive a 30-day free trial automatically. No OAuth token API yet \u2014 see https://3dogs.ai/auth.md",
    "contact": {
      "name": "Alan Finney",
      "email": "alan@3dogs.ai",
      "url": "https://3dogs.ai"
    },
    "termsOfService": "https://app.3dogs.ai/terms"
  },
  "servers": [
    {
      "url": "https://app.3dogs.ai"
    }
  ],
  "components": {
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "session",
        "description": "Flask signed session cookie obtained via POST /api/login. Include cookies on all authenticated requests."
      }
    }
  },
  "paths": {
    "/health": {
      "get": {
        "summary": "Service health",
        "description": "Public health/status endpoint. No authentication required.",
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "timestamp": "2026-07-23T06:14:26Z"
                }
              }
            }
          }
        }
      }
    },
    "/api/signup": {
      "post": {
        "summary": "Create an account",
        "description": "Creates a new account with an automatic 30-day free trial (no confirmation code required). Agents may register on behalf of a user only with that user's explicit consent. Returns 409 if the email already has an account.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account created, session started; complete Terms acceptance at /onboard before first use"
          },
          "409": {
            "description": "Account already exists \u2014 log in instead"
          }
        },
        "security": [],
        "x-public-reason": "Intentionally unauthenticated: an agent or person with no account must be able to use it."
      }
    },
    "/api/login": {
      "post": {
        "summary": "Log in (start a session)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Session cookie set"
          },
          "401": {
            "description": "Invalid credentials"
          }
        },
        "security": [],
        "x-public-reason": "Intentionally unauthenticated: an agent or person with no account must be able to use it."
      }
    },
    "/api/whoami": {
      "get": {
        "summary": "Current session identity",
        "responses": {
          "200": {
            "description": "Returns the logged-in email, or an anonymous indicator"
          }
        }
      }
    },
    "/intake": {
      "post": {
        "summary": "Submit a decision case",
        "description": "Starts a full multi-model adversarial analysis. Requires an active session and an active plan or trial. Write in ANY language \u2014 the analysis returns in English. The final report is delivered by email as a PDF and appears in the account dashboard; progress can be watched live at /watch?case=<case_id>. Analysis takes ~5-40+ minutes depending on mode.",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "q1"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "description": "Account email (matches the session)"
                  },
                  "q1": {
                    "type": "string",
                    "description": "The decision, in full \u2014 situation, options, constraints, numbers, deadlines. Any language, formulas, and pasted spreadsheet data are all accepted."
                  },
                  "q2": {
                    "type": "string",
                    "description": "Optional guided field (business background). Fields q2-q26 are optional structured intake prompts shown in guided mode; q1 alone is sufficient."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "",
                      "direct",
                      "deep"
                    ],
                    "description": "\"\" = 3Dogs decides (adaptive, may ask clarifying questions), \"direct\" = no follow-up questions single-panel (~5 min), \"deep\" = forced 3-panel ensemble with clarification rounds (slow, most rigorous)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Case accepted; returns case_id"
          },
          "302": {
            "description": "Not authenticated \u2014 redirected to login"
          },
          "402": {
            "description": "No active plan or trial"
          }
        }
      }
    },
    "/api/my-cases": {
      "get": {
        "summary": "List the account's cases",
        "description": "Returns the session account's cases with status, any pending clarification questions, PDF download links, and an account block (plan, days remaining).",
        "security": [
          {
            "sessionCookie": []
          }
        ],
        "responses": {
          "200": {
            "description": "Case list"
          }
        }
      }
    },
    "/pointer/scan.json": {
      "get": {
        "operationId": "scanAgentReadiness",
        "summary": "Scan a public website for AI-agent readiness",
        "description": "Eighteen live HTTP requests against the supplied domain. Returns per-check results with the exact request that produced each one, plus an integrity score (of what the site publishes, how much holds up) and a readiness score (how much exists at all). Free and unauthenticated. Typical response time twenty seconds.",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Domain or URL to scan, e.g. example.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Scan result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "root": {
                      "type": "string"
                    },
                    "score": {
                      "type": "number"
                    },
                    "discovery_only": {
                      "type": "number"
                    },
                    "grade": {
                      "type": "string"
                    },
                    "cats": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid url"
          },
          "429": {
            "description": "Three scans already running; retry shortly"
          }
        }
      }
    },
    "/pointer/scan": {
      "get": {
        "operationId": "scanAgentReadinessHtml",
        "summary": "Human-readable version of the same scan",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML report"
          }
        }
      }
    },
    "/pointer/fix-request": {
      "post": {
        "operationId": "requestAgentReadinessFix",
        "summary": "Request the agent-readiness fix (included with Corporate; no payment taken)",
        "description": "Registers a request and returns a reference. No charge is made and no payment method is accepted here; a human confirms scope and handles payment separately.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain",
                  "email"
                ],
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "scan_id": {
                    "type": "string"
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Request recorded; reference returned"
          },
          "400": {
            "description": "domain and email are required"
          }
        },
        "security": [],
        "x-public-reason": "Intentionally unauthenticated: an agent or person with no account must be able to use it."
      }
    },
    "/pointer/result/{scan_id}.json": {
      "get": {
        "operationId": "getScanResult",
        "summary": "Retrieve a previous scan by id",
        "parameters": [
          {
            "name": "scan_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stored scan"
          },
          "404": {
            "description": "Unknown id"
          }
        }
      }
    }
  }
}