For developers & AI agents

The Obelisk API

One identity & security plane, fully discoverable. 87 endpoints across 15 surfaces — every one declares its method, path, auth, and shape. Humans read this page; agents read the same contract as JSON.

Start here

Everything an app or agent needs to use Obelisk is discoverable from a single request — no HTML scraping, no guesswork.

Base URL https://obeliskgate.com · Version obelisk-api-1

Authentication

Each endpoint declares one of four auth levels — a small closed vocabulary you can branch on:

LevelWhat it means
nonepublic
sessionobelisk_session cookie OR body.token
bearerOIDC access token (Authorization: Bearer)
ownersession + org owner/admin
ack-secretx-obelisk-ecosystem-ack header for Studio ecosystem acknowledgements

Bearer tokens are OIDC access tokens presented as Authorization: Bearer <token>. Session auth accepts the HttpOnly obelisk_session cookie (browser) or a token in the JSON body (server-to-server).

Discovery

Well-known entry points for clients and agents:

WhatURL
openid_configuration/.well-known/openid-configuration
oauth_protected_resource/.well-known/oauth-protected-resource
jwks/.well-known/jwks.json
manifest/api
openapi/openapi.json
agent_interface/.well-known/obelisk-agent
saml_idp_metadata/saml/idp/metadata
health/healthz
transparency/.well-known/obelisk-transparency.json
security_txt/.well-known/security.txt
agents_json/agents.json
llms_txt/.well-known/llms.txt
changelog/changelog?format=json
studio_ecosystem/studio/ecosystem/manifest.json

Release history

Public-safe product history for humans and agents, bound to the revision serving it when deploy metadata is available.

MethodEndpointAuthWhat it does
GET/changelognoneHuman release history (HTML; versioned JSON with ?format=json or Accept: application/json).

Authentication & OIDC

Passkey-first sign-in + OIDC.

MethodEndpointAuthWhat it does
GET/authnoneThe immersive sign-in/sign-up experience (HTML).
GET/auth/assertion-optionsnoneBegin a (usernameless) passkey sign-in.
query — user: optional account name
POST/auth/assertion-verifynoneComplete a passkey sign-in; returns the session + where to go (home).
body — user: optional; response: WebAuthn assertion; deviceId: optional
POST/auth/verify-sessionnoneServer-to-server: validate a session token; returns { ok, identityId }.
body — token: macaroon
GET/auth/userinfobearerOIDC userinfo for an access token.
POST/auth/magic/requestnoneRequest an email magic-link (where enabled).
body — email: string; dryRun: session-gated: return the link for the session's OWN verified email (founder at sensitive assurance: any email, receipted), don't send
GET/auth/magicnoneW272 — the magic-link landing: consumes the token on the requesting device, then hands off (back to the relying party when one is waiting).
query — token: string; return: validated relying-party return; project: display name
GET/auth/authorizenoneOIDC authorization endpoint (PKCE S256). W272: response_mode=web_message posts the code to the opener page from a popup; prompt=none|login; a live session fast-paths to one tap.
query — client_id: registered client; redirect_uri: exact registered callback; response_mode: query | web_message; prompt: none | login
POST/auth/authorize/directnoneW272 — the direct grant: a passkey assertion (or fresh registration) performed ON a registered relying party's page (WebAuthn related origins) becomes a one-time authorization code. CORS-scoped to the origin registered for client_id; PKCE S256; auth-throttled.
body — client_id: string; redirect_uri: string; code_challenge: S256; code_challenge_method: S256; state: string; nonce: optional; assertion: { user?, response }; registration: { user, response, signupToken? } — account creation in place

FedCM (browser-mediated sign-in)

W272 — Federated Credential Management: the browser shows the Obelisk account chooser inline on a registered relying party's page and hands it a signed ID token. No redirect, no popup, third-party-cookie-proof. Discovery anchor: /.well-known/web-identity.

MethodEndpointAuthWhat it does
GET/fedcm/config.jsonnoneProvider configuration (endpoints, branding, login_url).
GET/fedcm/accountssessionThe signed-in person's account(s); requires Sec-Fetch-Dest: webidentity (sent only by the browser's FedCM machinery).
GET/fedcm/client-metadatanonePrivacy/terms for a registered client; the request Origin must be registered to it.
query — client_id: string
POST/fedcm/assertionsessionMint an ES256 ID token (aud = client_id, nonce-bound, truthful obelisk.assurance) for ONE registered client whose registered origin equals the request Origin.
body — account_id: the session's identity; client_id: string; nonce: string
POST/fedcm/disconnectsessionThe person asked the browser to forget the link; acknowledged and receipted.
body — client_id: string; account_hint: string

Agent identity & proof

Register, key-bind, verify, publish, suspend, recover, and revoke AI agents, bots, automations, devices, and agent teams without claiming that behavior proves non-humanness.

MethodEndpointAuthWhat it does
GET/account/agentssessionAgent Studio (HTML): the owner's whole agent fleet — create, import, pair, and manage.
GET/account/agents/:agentIdsessionOne agent's deep-linkable profile page (HTML): declared runtime facts, proof keys, evidence, delegation, and the full management card. Unknown or foreign ids 404 identically.
POST/auth/agents/proof/enroll/beginnoneBegin device-style enrollment with an agent-generated public JWK. Returns a short owner code; private key material is refused.
body — name: string; subjectKind: service_bot|automation|ai_agent|hybrid_agent|robot|device|agent_team|ephemeral_subagent; publicJwk: P-256/Ed25519 public JWK; visibility: private|unlisted|public
POST/auth/agents/proof/enroll/approvesessionPasskey-authorized accountable party approves the pending agent; identity remains pending until the agent proves its key.
body — enrollment_id: aen_...
POST/auth/agents/proof/enroll/completenoneAgent completes enrollment with a nonce-bound ES256 DPoP header. Returns its opaque Proof Link.
body — enrollment_id: aen_...
POST/auth/agents/proof/enroll/statusnonePoll bounded enrollment state without learning owner details.
body — enrollment_id: aen_...
GET/agent/:proof_idnoneHuman-readable opt-in Proof Link. Private profiles 404; a URL is never a credential.
GET/agent/:proof_id.jsonnoneMachine proof vector plus W3C VC and A2A projections. Claims remain independent and freshness-scoped.
POST/api/agent-proof/challengenoneRequest a short-lived nonce for a visible active agent.
body — proof_id: opaque id
POST/api/agent-proof/verifynoneVerify current agent-key control with a one-use challenge and DPoP; returns a short-lived signed proof token when signing is available.
body — proof_id: opaque id; challenge_id: apc_...; audience: optional verifier audience
POST/api/agent-proof/runnoneBind a client-built, commitment-only run proof to the active agent key and one-use nonce; returns a short-lived Obelisk-signed run token. Raw task/input/output stay client-side.
body — proof_id: opaque id; challenge_id: purpose:run challenge; run_proof: obelisk-agent-run-proof-v1; audience: optional verifier audience
POST/auth/agents/proof/visibilitysessionSet profile privacy: private, unlisted, or public. Requires passkey-grade step-up.
POST/auth/agents/proof/lifecyclesessionSuspend, resume, mark compromised, or revoke. Compromise/revoke cascades to agent-bound API keys.
POST/auth/agents/proof/key-rotatesessionRotate a public key. Normal rotation requires proof of the current key; compromise recovery rotates first and resumes only from suspended state.
POST/auth/agents/proof/transfer/beginsessionSource owner suspends an agent and creates a short transfer code for one named target owner.
POST/auth/agents/proof/transfer/acceptsessionNamed target owner accepts with a separate passkey and fresh public JWK. The identity stays suspended until target passkey + new agent key co-sign resume.
POST/auth/agents/proof/dns-challengesessionGet the stable _obelisk-agent TXT record that proves domain control for this agent. Publish it, then dns-verify.
body — agent_id: agt_...; domain: example.com
POST/auth/agents/proof/dns-verifysessionResolve the TXT record and, on match, append domain-control evidence (channel_control leaves 'declared').
body — agent_id: agt_...; domain: example.com
POST/auth/agents/proof/a2a-discoversessionFetch an A2A agent card (SSRF-guarded, 128KB cap) and append descriptor-integrity evidence; fills declared a2aCardUrl/capabilities only where empty.
body — agent_id: agt_...; url: https card URL
GET/api/agent-trust/bundlenoneThis authority's claim registry as a signed trust bundle (JWS via jwks_uri) for federation peers to pin and import.

Account

The universal Obelisk account — one identity across every app.

MethodEndpointAuthWhat it does
GET/accountsessionYour account page (HTML; JSON with ?format=json → the full profile).
GET/account/exportsessionDownload a portable, secret-free copy of your account (JSON).
POST/auth/profilesessionSet your display name.
body — displayName: string
POST/auth/account/renamesessionChange your username (old name stays a resolvable alias).
body — newUsername: string
POST/auth/preferencessessionMerge your preferences (theme/lang/contrast/motion/text/email).
body — preferences: object
POST/auth/passkeys/listsessionList your passkeys (no public keys).
POST/auth/passkeys/renamesessionRename a passkey.
body — credId: string; label: string
POST/auth/passkeys/removesessionRemove a passkey (never the last one).
body — credId: string
POST/auth/passkeys/add-optionssessionBegin adding a passkey to your account.
POST/auth/passkeys/add-verifysessionFinish adding a passkey.
body — response: WebAuthn attestation
POST/auth/totp/setupsessionBegin TOTP setup (pending) → { secret, uri, qrSvg }.
POST/auth/totp/confirmsessionConfirm + activate TOTP with a code.
body — code: 6 digits
POST/auth/totp/disablesessionTurn off TOTP.
POST/auth/recovery/regeneratesessionGenerate new backup codes (shown once).
POST/auth/sessions/revokesessionRevoke a session.
body — identifier: string
POST/auth/devices/revokesessionSign out a whole device — revokes every session it holds, then drops it from the device ledger.
body — deviceId: string
POST/auth/signoutsessionClear the session cookie.

Organizations

Register a business/website for its own Obelisk Rating; manage a team.

MethodEndpointAuthWhat it does
POST/auth/orgs/createsessionCreate an organization (you become owner).
body — name: string; website: optional url
GET/org/:slugsessionOrg dashboard (HTML; JSON with ?format=json), member-gated.
POST/org/:slug/scanownerRun an external security-posture scan → an Obelisk Rating. Scan a specific site with { siteId } or the primary by default.
body — website: optional override; siteId: optional registered-site id
POST/org/:slug/websites/addownerAdd a website this org owns (first becomes primary).
body — url: https url; label: optional
POST/org/:slug/websites/removeownerRemove a registered site by id.
body — siteId: string
POST/org/:slug/websites/primaryownerPromote a site to primary (the org headline rating tracks it).
body — siteId: string
POST/org/:slug/members/roleownerChange a member's role. Owner-only for owner changes; the last owner can't be demoted.
body — user: identityId; role: member|admin|owner
POST/org/:slug/members/removeownerRemove a member. The last owner can never be removed.
body — user: identityId
POST/org/:slug/inviteownerCreate a role-scoped invite link.
body — role: member|admin; email: optional
POST/org/:slug/invite/revokeownerRevoke an invite.
body — code: string
POST/org/:slug/settingsownerRename the organization and/or set its description. The @slug handle is permanent; member profiles update automatically.
body — name: string ≤80; description: optional string ≤280
POST/org/:slug/leavesessionLeave the organization (self-service). The last owner must transfer ownership first; your agents scoped to it become personal.
POST/org/:slug/transfer-ownershipownerHand ownership to an existing member (passkey step-up required). You stay on as admin.
body — user: identityId
GET/join/:codenoneAccept an invite (signs you in first if needed).

App registration

Self-serve OAuth/OIDC client registration — the developer portal (/account/apps) + its API.

MethodEndpointAuthWhat it does
GET/account/appssessionThe hosted app-registration portal (HTML): register apps, list, copy config, revoke.
POST/auth/registersessionRFC 7591 dynamic client registration → { client_id, ... }. Optional { org } scopes the app to an organization you administer (else your personal tenant). Requires OBELISK_DCR=open + tenant enforcement.
body — client_name: string; redirect_uris: https[]; obelisk_project_trust_profile: object; resource_uris: https[]; org: optional org slug
POST/auth/apps/listsessionList apps in tenants you control (personal + admin orgs). Never returns a secret.
POST/auth/apps/revokesessionRevoke an app you own → status:revoked.
body — clientId: string

Per-project profile

The on-top layer: each project's own per-user profile slice, scoped to its OIDC client.

MethodEndpointAuthWhat it does
GET/api/project-profilebearerRead this project's profile slice for the token's user → { sub, project, profile }.
POST/api/project-profilebearerShallow-merge into this project's slice.
body — profile: object

Studio ecosystem

Studio-wide Obelisk rollout truth: declared, observed, required, migration cargo, and receipt-backed acknowledgement state.

MethodEndpointAuthWhat it does
GET/studio/ecosystem/manifest.jsonnoneFleet manifest for Studio Ops: every registered project, required Obelisk versions, observed status, and migration state.
GET/studio/ecosystem/projects/:slugnoneOne project's ecosystem profile row from the canonical manifest.
GET/studio/ecosystem/projects/:slug/migrationnoneContent-addressed recipient-owned Ark migration cargo for one project.
POST/studio/ecosystem/projects/:slug/ackack-secretRecord a recipient-owned migration acknowledgement. Requires x-obelisk-ecosystem-ack; writes an ecosystem-ack receipt.
body — result: applied|already-current|rejected|blocked; cargoDigest: sha256:...; repoCommit: optional commit; evidence: optional object

MCP tool server

Obelisk's public Model Context Protocol tool server — read-only trust tools over JSON-RPC 2.0, plus the plain catalogue.

MethodEndpointAuthWhat it does
POST/mcpnoneJSON-RPC 2.0 MCP endpoint (initialize, tools/list, tools/call). Read-only trust tools; stateful per-client rate limit.
body — jsonrpc: the literal "2.0"; id: number|string; method: initialize | tools/list | tools/call; params: tools/call: { name, arguments }
GET/mcp/toolsnoneThe plain JSON tool catalogue: every tool's name, description, and input schema.

Receipt proof plane

Public receipt-by-hash lookup with sorted-Merkle inclusion proofs against the tamper-evident ledger. By-hash only — no enumeration.

MethodEndpointAuthWhat it does
GET/api/proofnoneSelf-describing: how to verify, and where the transparency head to pin lives.
GET/api/proof/:hashnoneReceipt lookup by 64-hex currentHash → chain position + a Merkle inclusion proof {leafHash, path, root}. Hash material only; never bodies, actors, or intents.

SAML federation (Obelisk as your IdP)

Obelisk as the SAML 2.0 IdP for downstream platforms (GitHub, Slack, AWS, …).

MethodEndpointAuthWhat it does
GET/saml/idp/metadatanoneIdP metadata: entity ID, SSO URL, and the pinned X.509 signing certificate — hand this URL to any SAML service provider.
GET/saml/idp/ssononeSAML 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)

The verified seal

The verified “Secured by Obelisk Gate” seal + per-site verification pages.

MethodEndpointAuthWhat it does
GET/embed/seal.jsnoneDrop-in loader: one script tag renders the live seal card on a relying party's page.
GET/embed/v1/sealnoneThe framed seal card itself (rendered live from obeliskgate.com; can't be forged).
GET/verify/:rpnonePublic verification page for a relying party — anyone can confirm the seal is genuine.

Website scan

The public website posture scan (the same engine behind the org Rating).

MethodEndpointAuthWhat it does
POST/api/scannoneScan 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

Reach the team.

MethodEndpointAuthWhat it does
POST/api/contactnoneSend a message to the team (form-encoded: name, email, subject, message). Honeypot-protected, throttled.
body — name: string; email: string; subject: string?; message: string

Content negotiation & errors

Selected account, organization, API-manifest, and changelog surfaces return JSON with ?format=json or Accept: application/json; static editorial pages remain HTML.

Failures share one shape — { ok:false, reason:<code>, message?:<human> } on failures; HTTP status mirrors it. — and the HTTP status mirrors it, so a client can branch on either.

The machine-readable contract

This whole reference is generated from one manifest. Fetch it as JSON and an agent can discover and use every surface without reading a line of HTML:

curl -s https://obeliskgate.com/api?format=json

Building an agent? Start with Obelisk for agents, then the per-project profile contract. Questions → Help Center.