{"openapi":"3.0.3","info":{"title":"CorroborateMe API","version":"0.1.0","description":"Identity for humans, apps, and agents\n\nConsumers are **any** HTTP client: backend services, SPAs, mobile apps, scripts, or AI agents.\nAgents are optional — the same REST surface powers console sessions, API keys, OIDC apps, and login-links.\n\nAuth: Bearer session JWT (console), company end-user JWT (login-link IdP), or API key (`aa_…`).\nInteractive UI: https://corroborate-me.cnrcode.com/swagger · Agent index: https://corroborate-me.cnrcode.com/llms.txt · Human guide: https://corroborate-me.cnrcode.com/docs"},"servers":[{"url":"https://corroborate-me.cnrcode.com"}],"tags":[{"name":"Discovery","description":"Health, config, OpenAPI"},{"name":"Console auth","description":"Human product login (platform login-link + session)"},{"name":"Agents","description":"Humanless company bootstrap"},{"name":"Companies","description":"Tenants, claim, API keys"},{"name":"Billing","description":"Stripe checkout, portal, machine-pay, budget"},{"name":"OIDC","description":"Register relying-party clients"},{"name":"Integrations","description":"Encrypted vault (Google/Apple secrets, etc.)"},{"name":"Login links","description":"Mint one-time human login URLs; poll / SSE / webhook notify"},{"name":"Login-link IdP","description":"Public end-user auth for a pending login-link (password, OTP, social, passkey)"},{"name":"MCP","description":"Model Context Protocol JSON-RPC at /mcp"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Console session JWT, company end-user JWT, bootstrap JWT, or API key (aa_…)"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"details":{}}},"NotifyMethod":{"type":"string","enum":["webhook","redirect","post_message","form_post","poll","sse"]}}},"paths":{"/health":{"get":{"tags":["Discovery"],"security":[],"summary":"Health check","responses":{"200":{"description":"{ ok: true }"}}}},"/api/config":{"get":{"tags":["Discovery"],"security":[],"summary":"Public client config (Turnstile site key, plans, brand)","responses":{"200":{"description":"Config JSON"}}}},"/openapi.json":{"get":{"tags":["Discovery"],"security":[],"summary":"This OpenAPI document","responses":{"200":{"description":"OpenAPI 3 JSON"}}}},"/api/auth/console/start":{"post":{"tags":["Console auth"],"security":[],"summary":"Start console sign-in (mint platform login-link + redirect)","description":"Creates a login-link for PLATFORM_COMPANY_ID with redirect to /login/callback. Bot checks run on the login-link IdP, not this endpoint.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force_reauth":{"type":"boolean"}}}}}},"responses":{"200":{"description":"{ ok, loginUrl, sessionId, state, expiresAt }"},"503":{"description":"PLATFORM_COMPANY_ID unconfigured"}}}},"/api/auth/console/exchange":{"post":{"tags":["Console auth"],"security":[],"summary":"Exchange completed login-session for console JWT","description":"Server re-reads login_sessions (do not trust redirect query email/user_id). One-time consume.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["session_id","state"],"properties":{"session_id":{"type":"string"},"state":{"type":"string"}}}}}},"responses":{"200":{"description":"{ ok, token, userId, email }"},"401":{"description":"invalid_state / already_exchanged"}}}},"/api/auth/logout":{"post":{"tags":["Console auth"],"security":[],"summary":"Clear console session cookie","responses":{"200":{"description":"Logged out"}}}},"/api/me":{"get":{"tags":["Console auth"],"security":[{"bearerAuth":[]}],"summary":"Current console user","responses":{"200":{"description":"User profile"}}}},"/api/agents/bootstrap":{"post":{"tags":["Agents"],"security":[],"summary":"Start humanless company onboarding (bootstrap JWT)","description":"No outbound email. Next: POST /api/billing/machine-pay or /api/billing/checkout with the bootstrap Bearer, or /api/agents/bootstrap/complete when billing is bypassed.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"company_name":{"type":"string"},"contact_email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"{ bootstrapToken, expiresIn, next: { machinePay, checkout } }"},"429":{"description":"rate_limited"}}}},"/api/agents/bootstrap/complete":{"post":{"tags":["Agents"],"security":[{"bearerAuth":[]}],"summary":"Complete bootstrap → company + aa_ key (local/bypass path)","description":"Authorization: Bearer <bootstrapToken>","responses":{"200":{"description":"{ company, secret, keyId }"},"401":{"description":"invalid_bootstrap"}}}},"/api/companies":{"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Create company (console session)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}}}}}},"responses":{"200":{"description":"{ company }"}}},"get":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"List companies for console user","responses":{"200":{"description":"{ companies: [...] }"}}}},"/api/companies/{id}":{"get":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Get company","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Company"}}}},"/api/companies/{id}/claim":{"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Claim ownership of an agent-bootstrapped company","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Claimed"}}}},"/api/companies/{id}/keys":{"get":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"List API key metadata (secrets never returned)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ keys }"}}},"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Mint API key (aa_… shown once)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}}}}}},"responses":{"200":{"description":"{ id, secret, prefix }"}}}},"/api/companies/{id}/keys/{keyId}/revoke":{"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Revoke API key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok: true }"}}}},"/api/companies/{id}/members":{"get":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"List console members (owners, admins, co-creators)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ members, myRole }"}}},"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Invite a console user by email as owner (co-creator) or admin","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string"},"role":{"type":"string","enum":["owner","admin"],"default":"admin"}}}}}},"responses":{"200":{"description":"{ member }"},"403":{"description":"owner_required"},"409":{"description":"already_member"}}}},"/api/companies/{id}/members/{userId}/remove":{"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Remove a console member (owners only; cannot remove last owner)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok: true }"},"400":{"description":"last_owner"},"403":{"description":"owner_required"}}}},"/api/companies/{id}/delete":{"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Soft-delete company (owner only). 30-day grace then hard wipe of company + login-link PII.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ company } with deleted_at / purge_after"},"400":{"description":"already_deleted"},"403":{"description":"owner_required"}}}},"/api/companies/{id}/restore":{"post":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"Restore a soft-deleted company before purge_after (owner only). API keys stay revoked.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ company }"},"400":{"description":"not_deleted"},"403":{"description":"owner_required"}}}},"/api/companies/{id}/end-users":{"get":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"List login-link end-users (owner or admin console session)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ users }"}}}},"/api/companies/{id}/end-users/{userId}":{"delete":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"GDPR erase a login-link end-user (owner or admin). Removes user, OTPs, passkeys, sessions.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok: true }"},"404":{"description":"not_found"}}}},"/api/end-users":{"get":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"List login-link end-users (company API key or X-Company-Id)","responses":{"200":{"description":"{ users }"}}}},"/api/end-users/{userId}":{"delete":{"tags":["Companies"],"security":[{"bearerAuth":[]}],"summary":"GDPR erase login-link end-user via API key (controller DSR path)","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok: true }"},"404":{"description":"not_found"},"410":{"description":"company_deleted"}}}},"/api/billing/checkout":{"post":{"tags":["Billing"],"security":[{"bearerAuth":[]}],"summary":"Create Stripe Checkout URL (or local bypass grant)","description":"Console session, company API key, or bootstrap Bearer. Bootstrap path may mint company + secret.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"companyId":{"type":"string"}}}}}},"responses":{"200":{"description":"{ url? } or bypass payload"}}}},"/api/billing/portal":{"post":{"tags":["Billing"],"security":[{"bearerAuth":[]}],"summary":"Stripe Customer Portal URL","responses":{"200":{"description":"{ url }"}}}},"/api/billing/machine-pay":{"post":{"tags":["Billing"],"security":[{"bearerAuth":[]}],"summary":"Agent prepaid unlock (MPP) or local bypass","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sku":{"type":"string"}}}}}},"responses":{"200":{"description":"May include secret (aa_…) when completing bootstrap"}}}},"/api/billing/webhook":{"post":{"tags":["Billing"],"security":[],"summary":"Stripe webhook receiver (Stripe-Signature)","responses":{"200":{"description":"Ack"}}}},"/api/budget":{"get":{"tags":["Billing"],"security":[{"bearerAuth":[]}],"summary":"Remaining quotas for the company","responses":{"200":{"description":"Budget / entitlement"}}}},"/api/oidc/clients":{"post":{"tags":["OIDC"],"security":[{"bearerAuth":[]}],"summary":"Register OIDC relying-party client","description":"Your app trusts this product as IdP. Prefer public_client + PKCE for SPAs. Hosted IdP lives under /api/auth/* (Better Auth).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","redirect_uris"],"properties":{"name":{"type":"string"},"redirect_uris":{"type":"array","items":{"type":"string","format":"uri"}},"public_client":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Client; confidential clients return clientSecret once"},"402":{"description":"subscription / quota"}}},"get":{"tags":["OIDC"],"security":[{"bearerAuth":[]}],"summary":"List OIDC clients","responses":{"200":{"description":"{ clients }"}}}},"/api/integrations":{"post":{"tags":["Integrations"],"security":[{"bearerAuth":[]}],"summary":"Upsert encrypted integration secret","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider","secret"],"properties":{"provider":{"type":"string"},"label":{"type":"string"},"secret":{"type":"string"},"meta":{"type":"object"}}}}}},"responses":{"200":{"description":"{ id, prefix }"}}},"get":{"tags":["Integrations"],"security":[{"bearerAuth":[]}],"summary":"List integrations (prefixes only)","responses":{"200":{"description":"{ integrations }"}}}},"/api/login-links":{"post":{"tags":["Login links"],"security":[{"bearerAuth":[]}],"summary":"Create login-link session (one-time human login URL)","description":"poll + sse always available. Optional webhook/redirect/form_post/post_message. Default reuses company cookie (Continue-as); set force_reauth for fresh proof. End-user ids are cu_…","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"methods":{"type":"array","items":{"$ref":"#/components/schemas/NotifyMethod"}},"webhook_url":{"type":"string","format":"uri"},"redirect_uri":{"type":"string"},"form_post_uri":{"type":"string","format":"uri"},"post_message_origin":{"type":"string"},"state":{"type":"string"},"ttl_seconds":{"type":"number"},"force_reauth":{"type":"boolean","default":false},"reuse_session":{"type":"boolean","description":"Alias for !force_reauth"}}}}}},"responses":{"200":{"description":"{ session_id, login_url, methods, force_reauth, … }"},"400":{"description":"Allowlist / validation errors"},"402":{"description":"subscription_required / quota_exceeded"}}}},"/api/login-links/{id}":{"get":{"tags":["Login links"],"security":[{"bearerAuth":[]}],"summary":"Poll login-link status","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Status, user_id (cu_…), email, notify_result, errors"}}}},"/api/login-links/{id}/events":{"get":{"tags":["Login links"],"security":[{"bearerAuth":[]}],"summary":"SSE wait for completion (~25s then done|pending)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"text/event-stream"}}}},"/api/login-links/{id}/retry-webhook":{"post":{"tags":["Login links"],"security":[{"bearerAuth":[]}],"summary":"Retry signed webhook delivery","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Retry result"}}}},"/api/webhooks/allowlist":{"post":{"tags":["Login links"],"security":[{"bearerAuth":[]}],"summary":"Allowlist webhook/redirect/form_post URL prefix","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url_prefix"],"properties":{"url_prefix":{"type":"string","description":"e.g. https://hooks.example.com/ or cursor://"}}}}}},"responses":{"200":{"description":"Allowlisted"}}}},"/api/login-links/{id}/public":{"get":{"tags":["Login-link IdP"],"security":[],"summary":"Public session info for hosted login UI","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"company","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Company name, status, social flags, force_reauth, active_session?"}}}},"/api/login-links/{id}/password-login":{"post":{"tags":["Login-link IdP"],"security":[],"summary":"Email + password login (registered users)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"password":{"type":"string"},"company":{"type":"string"}}}}}},"responses":{"200":{"description":"Completes session + delivery"}}}},"/api/login-links/{id}/request-otp":{"post":{"tags":["Login-link IdP"],"security":[],"summary":"Request OTP (login | register | reset)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"{ ok }"}}}},"/api/login-links/{id}/verify-otp":{"post":{"tags":["Login-link IdP"],"security":[],"summary":"Verify OTP — login completes; register/reset → password_ticket","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Complete or ticket"}}}},"/api/login-links/{id}/set-password":{"post":{"tags":["Login-link IdP"],"security":[],"summary":"Set password with ticket → complete session","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Completed"}}}},"/api/login-links/{id}/complete":{"post":{"tags":["Login-link IdP"],"security":[{"bearerAuth":[]}],"summary":"Finish with existing company cookie (blocked if force_reauth)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Completed"}}}},"/api/login-links/{id}/passkey/auth/options":{"post":{"tags":["Login-link IdP"],"security":[],"summary":"WebAuthn assertion options","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PublicKeyCredentialRequestOptions"}}}},"/api/login-links/{id}/passkey/auth/verify":{"post":{"tags":["Login-link IdP"],"security":[],"summary":"Verify passkey → complete session","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Completed"}}}},"/api/login-links/{id}/passkey/register/options":{"post":{"tags":["Login-link IdP"],"security":[{"bearerAuth":[]}],"summary":"Passkey enrollment options (company end-user JWT)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PublicKeyCredentialCreationOptions"}}}},"/api/login-links/{id}/passkey/register/verify":{"post":{"tags":["Login-link IdP"],"security":[{"bearerAuth":[]}],"summary":"Verify passkey enrollment","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Enrolled"}}}},"/api/login-links/social/start":{"get":{"tags":["Login-link IdP"],"security":[],"summary":"Start Google or Apple OAuth for login-link","parameters":[{"name":"session","in":"query","required":true,"schema":{"type":"string"}},{"name":"company","in":"query","required":true,"schema":{"type":"string"}},{"name":"provider","in":"query","required":true,"schema":{"type":"string","enum":["google","apple"]}}],"responses":{"302":{"description":"Redirect to provider"}}}},"/mcp":{"post":{"tags":["MCP"],"security":[{"bearerAuth":[]}],"summary":"MCP Streamable HTTP (initialize, tools/list, tools/call)","description":"Bearer aa_… API key. Cloudflare Agents MCP Durable Object. Tools: agent_bootstrap, budget_get, billing_checkout, billing_machine_pay, billing_portal, keys_create, oauth_client_create, integration_upsert, integration_list, create_login_link, get_login_status, retry_login_webhook, webhook_allowlist_add.","responses":{"200":{"description":"JSON-RPC / SSE MCP result"}}}}}}