# CorroborateMe — full integrator brief Identity for humans, apps, and agents Audience: human developers **and** agents. Prefer REST + OpenAPI for apps; MCP is a convenience facade over the same capabilities. Human guide: https://corroborateme.com/docs Pricing: https://corroborateme.com/pricing Swagger UI: https://corroborateme.com/swagger OpenAPI: https://corroborateme.com/openapi.json Short index: https://corroborateme.com/llms.txt MCP discovery: https://corroborateme.com/.well-known/mcp.json ## Auth models | Who | Credential | Notes | |-----|------------|--------| | Console operator | Session JWT after OTP | Manage companies, billing, keys | | App / agent | `aa_…` API key | `Authorization: Bearer` | | Bootstrap (pre-key) | Bootstrap JWT (~15m) | From POST /api/agents/bootstrap | | Login-link end-user | Company session cookie/JWT | Id `cu_…`; not console `usr_…` | ## Zero-human onboarding ``` POST https://corroborateme.com/api/agents/bootstrap {"company_name":"Acme","contact_email":"ops@acme.example"} → bootstrapToken POST https://corroborateme.com/api/billing/machine-pay Authorization: Bearer {"sku":"pro_prepaid_30d"} → secret (aa_…) when settled / local bypass ``` Local: BILLING_DEV_BYPASS may allow POST /api/agents/bootstrap/complete with bootstrap Bearer. ## Login-link (prove a human) Mint `login_url`; human finishes on the hosted IdP. Notify via one or more methods. `poll` + `sse` always available. End-user ids are `cu_…`. Default reuses company cookie (Continue-as); set `force_reauth:true` for fresh proof. Prefer a client modal over pasting the URL into a model transcript. Iframes not supported. ### Recipe: poll / SSE (headless) ``` POST https://corroborateme.com/api/login-links Authorization: Bearer aa_… {"state":"job_1"} → login_url, session_id GET https://corroborateme.com/api/login-links/{session_id} → status, user_id, email GET https://corroborateme.com/api/login-links/{session_id}/events → SSE wait ~25s (done | pending) ``` ### Recipe: popup + postMessage (browser UI) ``` POST https://corroborateme.com/api/login-links Authorization: Bearer aa_… { "methods":["post_message"], "post_message_origin":"https://your-app.example", "state":"job_1" } → loginUrl, sessionId; open loginUrl via window.open; listen for message type agent_auth.login_completed (event.origin is https://corroborateme.com; targetOrigin on postMessage is your app) ``` ### Recipe: webhook (server-to-server) ``` POST https://corroborateme.com/api/webhooks/allowlist Authorization: Bearer aa_… {"url_prefix":"https://hooks.example.com/"} POST https://corroborateme.com/api/login-links Authorization: Bearer aa_… { "methods":["webhook"], "webhook_url":"https://hooks.example.com/corroborate-me", "state":"job_1" } ``` Webhook payload: `{type,session_id,company_id,state,user_id,email,claims}`. HMAC header `X-Agent-Auth-Signature` (hex SHA-256 of raw body). Retries on 408/429/5xx; then `POST …/retry-webhook`. ### Recipe: redirect / form_post ``` POST https://corroborateme.com/api/webhooks/allowlist {"url_prefix":"cursor://"} # or https://app.example.com/ POST https://corroborateme.com/api/login-links { "methods":["redirect"], "redirect_uri":"cursor://auth/done", "state":"job_1", "force_reauth":true } # or methods:["form_post"], form_post_uri:"https://app.example.com/callback" # fields: session_id, status, user_id, email, state (form_post not signed) ``` Console **Test login** tab runs the postMessage recipe live and shows the same copy-paste samples. ## Pricing (live from /api/config) | Plan | Amount | Period | |------|--------|--------| | Pro monthly | $5.99/mo USD | monthly | | CorroborateMe Pro Prepaid (30 days) (`pro_prepaid_30d`) | $5.99 USD | 30 days prepaid | Do not hardcode these amounts. GET /api/config and read plans.proMonthlyUsd / plans.agentSkus. Amounts may change. ## OIDC relying party (not live) You can register a client record with POST /api/oidc/clients. Hosted discovery at /api/auth/.well-known/openid-configuration and JWKS at /api/auth/jwks currently return 503 (better_auth_unavailable). Do not point production OIDC libraries at this host until those endpoints return a real document. Use login-link for end-user proof. ## MCP tools (Bearer aa_…) Endpoint: https://corroborateme.com/mcp (Streamable HTTP — MCP SDK / Cursor) - `agent_bootstrap`: Start humanless company onboarding (returns bootstrap token flow info) - `budget_get`: Remaining quotas for the authenticated company - `billing_checkout`: Create Stripe Checkout URL (or local bypass grant) - `billing_machine_pay`: Agent prepaid unlock when MPP enabled / local bypass - `billing_portal`: Stripe Customer Portal URL - `keys_create`: Mint a new aa_ API key (shown once) - `oauth_client_create`: Register an OIDC relying-party client - `integration_upsert`: Store encrypted integration secret (Google/Apple/etc.) - `integration_list`: List integrations (prefixes only, no secrets) - `create_login_link`: Mint one-time human login URL. Choose notify methods: webhook, redirect, post_message, form_post (poll+sse always on). Default reuses company cookie (Continue-as); set force_reauth for fresh login. No SMS. - `get_login_status`: Poll login-link session status (includes notify errors) - `retry_login_webhook`: Retry signed webhook delivery after a failed notify - `webhook_allowlist_add`: Allowlist a callback URL prefix (https webhooks/redirects or cursor:// deep links) ## Do not expose Operator admin (`/api/admin/*`, ADMIN_SECRET) is private — not in OpenAPI or this brief.