{"openapi":"3.1.0","info":{"title":"dots.id API","version":"1.0.0","description":"Portable identity, username-as-a-service, OAuth 2.1 + PKCE, MCP tools, and per-user sync/data for agentic apps. Treat OIDC `sub` as the stable account key.","contact":{"name":"dots.id","url":"https://www.dots.id/contact"},"license":{"name":"Proprietary","url":"https://www.dots.id/terms"}},"servers":[{"url":"https://www.dots.id"}],"tags":[{"name":"OAuth","description":"Authorization server endpoints"},{"name":"Identity","description":"Profile, username, bootstrap, and sync"},{"name":"MCP","description":"Model Context Protocol over HTTP"},{"name":"Context","description":"Portable dot context and search"},{"name":"Credits","description":"pute balance and spend"}],"paths":{"/.well-known/openid-configuration":{"get":{"tags":["OAuth"],"summary":"OpenID Connect discovery","responses":{"200":{"description":"OIDC metadata including scopes_supported"}}}},"/api/oauth/authorize":{"get":{"tags":["OAuth"],"summary":"Start OAuth authorization (PKCE S256)","parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string"}},{"name":"scope","in":"query","schema":{"type":"string"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","enum":["S256"]}},{"name":"state","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to consent or login"},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/api/oauth/token":{"post":{"tags":["OAuth"],"summary":"Exchange authorization code, refresh token, or device code","description":"grant_type: `authorization_code` (with PKCE `code_verifier`), `refresh_token` (rotating; reuse revokes the family), or `urn:ietf:params:oauth:grant-type:device_code` (returns `authorization_pending` / `slow_down` / `access_denied` / `expired_token` while pending).","responses":{"200":{"description":"Access token response"},"400":{"description":"Token error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/api/oauth/userinfo":{"get":{"tags":["OAuth"],"summary":"OIDC userinfo","description":"Scoped identity claims plus `identity_stage`, `dots_id_status`, `wallet_confirmed`, and `mcp` / `bootstrap` URLs. The `listen` claim appears with the `listen` scope. Portable context is not in userinfo; use GET /api/identity/bootstrap or MCP `whoami`.","security":[{"oauth2":["openid","profile"]}],"responses":{"200":{"description":"User claims keyed by OIDC sub"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/api/oauth/register":{"post":{"tags":["OAuth"],"summary":"Dynamic client registration","responses":{"201":{"description":"Registered OAuth client"},"400":{"description":"Registration error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/api/oauth/device":{"post":{"tags":["OAuth"],"summary":"Start RFC 8628 device authorization (bots, CLIs, chat agents)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_id"],"properties":{"client_id":{"type":"string"},"scope":{"type":"string"},"state":{"type":"string"}}}}}},"responses":{"200":{"description":"device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval. Poll POST /api/oauth/token with grant_type=urn:ietf:params:oauth:grant-type:device_code until the user approves at /oauth/device."}}}},"/api/identity/bootstrap":{"get":{"tags":["Identity"],"summary":"Agent login snapshot (Bearer)","security":[{"oauth2":["openid","profile","context:read"]}],"responses":{"200":{"description":"Identity, color, connections, and optional context"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/api/identity/username":{"get":{"tags":["Identity"],"summary":"Check username availability","security":[{"oauth2":["username:create"]}],"parameters":[{"name":"username","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Availability result"},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}},"post":{"tags":["Identity"],"summary":"Claim a permanent dots.id username","security":[{"oauth2":["username:create"]}],"responses":{"200":{"description":"Username created"},"409":{"description":"Username unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/api/identity/context":{"get":{"tags":["Context"],"summary":"Read or search portable context","security":[{"oauth2":["context:read"]}],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Context rows or search hits"}}},"post":{"tags":["Context"],"summary":"Append context for the authorized app","security":[{"oauth2":["context:write"]}],"responses":{"201":{"description":"Context stored"}}}},"/api/pute/balance":{"get":{"tags":["Credits"],"summary":"Read pute credit balance","security":[{"oauth2":["pute:read"]}],"responses":{"200":{"description":"Balance"}}}},"/mcp":{"post":{"tags":["MCP"],"summary":"MCP streamable HTTP (tools: whoami, search, recent, remember)","description":"`whoami` accepts any valid dots token. `search` and `recent` require `context:read`; `remember` requires `context:write`. Unauthenticated calls return 401 with RFC 9728 `resource_metadata`.","security":[{"oauth2":["openid","context:read"]},{"oauth2":["openid","context:read","context:write"]}],"responses":{"200":{"description":"MCP JSON-RPC response"},"401":{"description":"Unauthorized with RFC 9728 resource metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}}},"components":{"securitySchemes":{"oauth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://www.dots.id/api/oauth/authorize","tokenUrl":"https://www.dots.id/api/oauth/token","scopes":{"openid":"Verify your identity","profile":"Access your username and basic profile info","username:create":"Check availability and create your permanent dots.id username","email":"Access your email address","wallet":"Access your connected wallet address","social:twitter":"Access your connected Twitter/X username","social:instagram":"Access your connected Instagram username","social:google":"Access your connected Google account info","listen":"Read connected listening sources and recent plays","data:read":"Read data this app has stored in your personal database","data:write":"Store data in your personal database","files:read":"List and download files in this app's dots-blob namespace","files:write":"Upload, move, and delete files in this app's dots-blob namespace","files:share":"Share files with dots people, orgs, and groups","context:read":"Read your dots context and history","context:write":"Append to your dots context and history","pute:read":"See your pute credit balance","pute:spend":"Spend pute credits on your behalf","pute:topup":"Start a checkout to add pute credits to your balance","mcp:use":"Call MCP servers connected to your dots identity","cosign":"Vouch for others and co-sign them into your dots org","delegate":"Grant scoped, capped access to other dots or agents on your behalf","org:act":"Take whitelisted actions as a dots org you belong to","org:admin":"Manage members, roles, and grants for a dots org","offline_access":"Maintain access when you are not actively using the app"}}}}},"schemas":{"OAuthError":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"error_description":{"type":"string"}}}}},"externalDocs":{"description":"Full REST reference and agent instructions","url":"https://www.dots.id/docs/api"}}