{
  "service": "Obelisk",
  "tagline": "Full-circle security for the agent era — a unified identity & security plane. Security you can prove, not just promise.",
  "description": "Passkey-first identity, one OIDC provider, tamper-evident receipts, a live security Rating, organizations, and a per-project profile layer. One identity across the whole ecosystem.",
  "version": "obelisk-api-1",
  "baseUrl": "https://obeliskgate.com",
  "forAgents": {
    "start_here": "https://obeliskgate.com/api",
    "guide": "https://obeliskgate.com/agents",
    "integrate": "https://obeliskgate.com/developers",
    "works_with_your_database": "https://obeliskgate.com/developers#database",
    "agent_interface": "https://obeliskgate.com/agent",
    "principles": [
      "passkey-first / WebAuthn",
      "no project-side secrets",
      "tamper-evident receipts",
      "sender-bound tokens (DPoP, RFC 9449) opt-in",
      "post-quantum migration-ready"
    ],
    "auth_vocabulary": {
      "none": "public",
      "session": "obelisk_session cookie OR body.token",
      "bearer": "OIDC access token (Authorization: Bearer)",
      "owner": "session + org owner/admin"
    },
    "token_binding": "DPoP (RFC 9449), opt-in: send a DPoP proof header at /auth/token and the access token binds to your key (cnf.jkt); protected calls then require token + fresh proof.",
    "content_negotiation": "Selected account, organization, API-manifest, and changelog surfaces return JSON with ?format=json or Accept: application/json; static editorial pages remain HTML.",
    "error_shape": "{ ok:false, reason:<code>, message?:<human> } on failures; HTTP status mirrors it."
  },
  "discovery": {
    "openid_configuration": "https://obeliskgate.com/.well-known/openid-configuration",
    "jwks": "https://obeliskgate.com/.well-known/jwks.json",
    "manifest": "https://obeliskgate.com/api",
    "agent_interface": "https://obeliskgate.com/.well-known/obelisk-agent",
    "saml_idp_metadata": "https://obeliskgate.com/saml/idp/metadata",
    "health": "https://obeliskgate.com/healthz",
    "transparency": "https://obeliskgate.com/.well-known/obelisk-transparency.json",
    "security_txt": "https://obeliskgate.com/.well-known/security.txt",
    "changelog": "https://obeliskgate.com/changelog?format=json"
  },
  "pages": {
    "developers": "https://obeliskgate.com/developers",
    "integrate_with_your_db": "https://obeliskgate.com/developers#database",
    "pricing": "https://obeliskgate.com/pricing",
    "help": "https://obeliskgate.com/help",
    "faq": "https://obeliskgate.com/help/faq",
    "security": "https://obeliskgate.com/security",
    "about": "https://obeliskgate.com/about",
    "changelog": "https://obeliskgate.com/changelog"
  },
  "contracts": {
    "project_profile": "https://obeliskgate.com/developers#database"
  },
  "surfaces": {
    "release_history": {
      "summary": "Public-safe product history for humans and agents, bound to the revision serving it when deploy metadata is available.",
      "endpoints": [
        {
          "method": "GET",
          "path": "/changelog",
          "auth": "none",
          "summary": "Human release history (HTML; versioned JSON with ?format=json or Accept: application/json)."
        }
      ]
    },
    "auth": {
      "summary": "Passkey-first sign-in + OIDC.",
      "endpoints": [
        {
          "method": "GET",
          "path": "/auth",
          "auth": "none",
          "summary": "The immersive sign-in/sign-up experience (HTML)."
        },
        {
          "method": "GET",
          "path": "/auth/assertion-options",
          "auth": "none",
          "summary": "Begin a (usernameless) passkey sign-in.",
          "query": {
            "user": "optional account name"
          }
        },
        {
          "method": "POST",
          "path": "/auth/assertion-verify",
          "auth": "none",
          "summary": "Complete a passkey sign-in; returns the session + where to go (home).",
          "body": {
            "user": "optional",
            "response": "WebAuthn assertion",
            "deviceId": "optional"
          }
        },
        {
          "method": "POST",
          "path": "/auth/verify-session",
          "auth": "none",
          "summary": "Server-to-server: validate a session token; returns { ok, identityId }.",
          "body": {
            "token": "macaroon"
          }
        },
        {
          "method": "GET",
          "path": "/auth/userinfo",
          "auth": "bearer",
          "summary": "OIDC userinfo for an access token."
        },
        {
          "method": "POST",
          "path": "/auth/magic/request",
          "auth": "none",
          "summary": "Request an email magic-link (where enabled).",
          "body": {
            "email": "string",
            "dryRun": "session-gated: return the link, don't send"
          }
        }
      ]
    },
    "account": {
      "summary": "The universal Obelisk account — one identity across every app.",
      "endpoints": [
        {
          "method": "GET",
          "path": "/account",
          "auth": "session",
          "summary": "Your account page (HTML; JSON with ?format=json → the full profile)."
        },
        {
          "method": "GET",
          "path": "/account/export",
          "auth": "session",
          "summary": "Download a portable, secret-free copy of your account (JSON)."
        },
        {
          "method": "POST",
          "path": "/auth/profile",
          "auth": "session",
          "summary": "Set your display name.",
          "body": {
            "displayName": "string"
          }
        },
        {
          "method": "POST",
          "path": "/auth/account/rename",
          "auth": "session",
          "summary": "Change your username (old name stays a resolvable alias).",
          "body": {
            "newUsername": "string"
          }
        },
        {
          "method": "POST",
          "path": "/auth/preferences",
          "auth": "session",
          "summary": "Merge your preferences (theme/lang/contrast/motion/text/email).",
          "body": {
            "preferences": "object"
          }
        },
        {
          "method": "POST",
          "path": "/auth/passkeys/list",
          "auth": "session",
          "summary": "List your passkeys (no public keys)."
        },
        {
          "method": "POST",
          "path": "/auth/passkeys/rename",
          "auth": "session",
          "summary": "Rename a passkey.",
          "body": {
            "credId": "string",
            "label": "string"
          }
        },
        {
          "method": "POST",
          "path": "/auth/passkeys/remove",
          "auth": "session",
          "summary": "Remove a passkey (never the last one).",
          "body": {
            "credId": "string"
          }
        },
        {
          "method": "POST",
          "path": "/auth/passkeys/add-options",
          "auth": "session",
          "summary": "Begin adding a passkey to your account."
        },
        {
          "method": "POST",
          "path": "/auth/passkeys/add-verify",
          "auth": "session",
          "summary": "Finish adding a passkey.",
          "body": {
            "response": "WebAuthn attestation"
          }
        },
        {
          "method": "POST",
          "path": "/auth/totp/setup",
          "auth": "session",
          "summary": "Begin TOTP setup (pending) → { secret, uri, qrSvg }."
        },
        {
          "method": "POST",
          "path": "/auth/totp/confirm",
          "auth": "session",
          "summary": "Confirm + activate TOTP with a code.",
          "body": {
            "code": "6 digits"
          }
        },
        {
          "method": "POST",
          "path": "/auth/totp/disable",
          "auth": "session",
          "summary": "Turn off TOTP."
        },
        {
          "method": "POST",
          "path": "/auth/recovery/regenerate",
          "auth": "session",
          "summary": "Generate new backup codes (shown once)."
        },
        {
          "method": "POST",
          "path": "/auth/sessions/revoke",
          "auth": "session",
          "summary": "Revoke a session.",
          "body": {
            "identifier": "string"
          }
        },
        {
          "method": "POST",
          "path": "/auth/devices/revoke",
          "auth": "session",
          "summary": "Sign out a whole device — revokes every session it holds, then drops it from the device ledger.",
          "body": {
            "deviceId": "string"
          }
        },
        {
          "method": "POST",
          "path": "/auth/signout",
          "auth": "session",
          "summary": "Clear the session cookie."
        }
      ]
    },
    "organizations": {
      "summary": "Register a business/website for its own Obelisk Rating; manage a team.",
      "endpoints": [
        {
          "method": "POST",
          "path": "/auth/orgs/create",
          "auth": "session",
          "summary": "Create an organization (you become owner).",
          "body": {
            "name": "string",
            "website": "optional url"
          }
        },
        {
          "method": "GET",
          "path": "/org/:slug",
          "auth": "session",
          "summary": "Org dashboard (HTML; JSON with ?format=json), member-gated."
        },
        {
          "method": "POST",
          "path": "/org/:slug/scan",
          "auth": "owner",
          "summary": "Run an external security-posture scan → an Obelisk Rating for the website.",
          "body": {
            "website": "optional override"
          }
        },
        {
          "method": "POST",
          "path": "/org/:slug/invite",
          "auth": "owner",
          "summary": "Create a role-scoped invite link.",
          "body": {
            "role": "member|admin",
            "email": "optional"
          }
        },
        {
          "method": "POST",
          "path": "/org/:slug/invite/revoke",
          "auth": "owner",
          "summary": "Revoke an invite.",
          "body": {
            "code": "string"
          }
        },
        {
          "method": "GET",
          "path": "/join/:code",
          "auth": "none",
          "summary": "Accept an invite (signs you in first if needed)."
        }
      ]
    },
    "project_profile": {
      "summary": "The on-top layer: each project's own per-user profile slice, scoped to its OIDC client.",
      "endpoints": [
        {
          "method": "GET",
          "path": "/api/project-profile",
          "auth": "bearer",
          "summary": "Read this project's profile slice for the token's user → { sub, project, profile }."
        },
        {
          "method": "POST",
          "path": "/api/project-profile",
          "auth": "bearer",
          "summary": "Shallow-merge into this project's slice.",
          "body": {
            "profile": "object"
          }
        }
      ]
    },
    "federation": {
      "summary": "Obelisk as the SAML 2.0 IdP for downstream platforms (GitHub, Slack, AWS, …).",
      "endpoints": [
        {
          "method": "GET",
          "path": "/saml/idp/metadata",
          "auth": "none",
          "summary": "IdP metadata: entity ID, SSO URL, and the pinned X.509 signing certificate — hand this URL to any SAML service provider."
        },
        {
          "method": "GET",
          "path": "/saml/idp/sso",
          "auth": "none",
          "summary": "SAML sign-on endpoint: authenticates passkey-first, then auto-POSTs an RSA-SHA256-signed assertion to the SP's ACS.",
          "query": {
            "SAMLRequest": "SP AuthnRequest (redirect binding)"
          }
        }
      ]
    },
    "seal": {
      "summary": "The verified “Secured by Obelisk Gate” seal + per-site verification pages.",
      "endpoints": [
        {
          "method": "GET",
          "path": "/embed/seal.js",
          "auth": "none",
          "summary": "Drop-in loader: one script tag renders the live seal card on a relying party's page."
        },
        {
          "method": "GET",
          "path": "/embed/v1/seal",
          "auth": "none",
          "summary": "The framed seal card itself (rendered live from obeliskgate.com; can't be forged)."
        },
        {
          "method": "GET",
          "path": "/verify/:rp",
          "auth": "none",
          "summary": "Public verification page for a relying party — anyone can confirm the seal is genuine."
        }
      ]
    },
    "scan": {
      "summary": "The public website posture scan (the same engine behind the org Rating).",
      "endpoints": [
        {
          "method": "POST",
          "path": "/api/scan",
          "auth": "none",
          "summary": "Scan a public https:// website's security posture → a rating with concrete levers. SSRF-guarded, throttled per client.",
          "body": {
            "url": "public https:// website (domains only)"
          }
        }
      ]
    },
    "contact": {
      "summary": "Reach the team.",
      "endpoints": [
        {
          "method": "POST",
          "path": "/api/contact",
          "auth": "none",
          "summary": "Send a message to the team (form-encoded: name, email, subject, message). Honeypot-protected, throttled.",
          "body": {
            "name": "string",
            "email": "string",
            "subject": "string?",
            "message": "string"
          }
        }
      ]
    }
  }
}