{"openapi":"3.1.0","info":{"title":"ServersWallet API","version":"0.1.0","description":"Team credential wallet for servers. Secrets are envelope-encrypted at rest; POST /credentials/{id}/reveal is the only endpoint returning plaintext and every reveal is audit-logged."},"servers":[{"url":"/"}],"security":[{"bearerAuth":[]},{"cookieAuth":[]}],"paths":{"/api/v1/health":{"get":{"summary":"Health check (no auth)","responses":{"200":{"description":"OK"}}}},"/api/v1/me":{"get":{"summary":"Who am I? Validates your key/session","responses":{"200":{"description":"Principal"},"401":{"description":"Unauthorized"}}}},"/api/v1/me/2fa":{"get":{"summary":"2FA status for the session user (enabled, recovery codes left)","responses":{"200":{"description":"Status"}}},"post":{"summary":"Start 2FA setup: returns { secret, otpauthUri } (session only)","responses":{"201":{"description":"Pending secret"}}}},"/api/v1/me/2fa/enable":{"post":{"summary":"Activate 2FA with a valid code. Body: { code }. Returns recovery codes once","responses":{"200":{"description":"{ enabled, recoveryCodes }"},"401":{"description":"Wrong code"}}}},"/api/v1/me/2fa/disable":{"post":{"summary":"Turn off 2FA. Body: { password }","responses":{"200":{"description":"{ disabled }"}}}},"/api/v1/servers":{"get":{"summary":"List servers (credentials attached, never plaintext secrets)","parameters":[{"name":"q","in":"query","schema":{"type":"string"},"description":"Search name/hostname/os"},{"name":"environment","in":"query","schema":{"type":"string"}},{"name":"tag","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Array of servers"}}},"post":{"summary":"Create server (write scope)","responses":{"201":{"description":"Created"},"403":{"description":"Read-only key"}}}},"/api/v1/servers/{id}":{"get":{"summary":"Get server with credentials","responses":{"200":{"description":"Server"},"404":{"description":"Not found"}}},"patch":{"summary":"Update server (write scope)","responses":{"200":{"description":"Updated"}}},"delete":{"summary":"Delete server + credentials (write scope)","responses":{"200":{"description":"Deleted"}}}},"/api/v1/credentials":{"post":{"summary":"Create credential (write scope). `secret` is encrypted before storage.","responses":{"201":{"description":"Created (no secret echoed)"}}}},"/api/v1/credentials/{id}":{"get":{"summary":"Get credential metadata (no secret)","responses":{"200":{"description":"Credential"}}},"patch":{"summary":"Update credential; pass new `secret` to re-encrypt (write scope)","responses":{"200":{"description":"Updated"}}},"delete":{"summary":"Delete credential (write scope)","responses":{"200":{"description":"Deleted"}}}},"/api/v1/credentials/{id}/reveal":{"post":{"summary":"Reveal plaintext secret — audited","responses":{"200":{"description":"{ id, label, secretType, secret }"}}}},"/api/v1/env":{"get":{"summary":"List env vars (metadata only, never values)","parameters":[{"name":"environment","in":"query","description":"Filter by environment"},{"name":"app","in":"query","description":"Filter by app/service"}],"responses":{"200":{"description":"Array of env vars"}}},"post":{"summary":"Bulk upsert: { vars: [{ environment?, app?, name, value, description? }] } (write scope). Old values archived as versions","responses":{"201":{"description":"{ created, updated, items }"},"402":{"description":"Plan env-var limit"}}}},"/api/v1/env/export":{"get":{"summary":"Plain dotenv text — eval $(curl …). Audited (count only)","parameters":[{"name":"environment","in":"query","description":"Filter by environment"},{"name":"app","in":"query","description":"Filter by app/service"}],"responses":{"200":{"description":"text/plain dotenv, Cache-Control: no-store"}}}},"/api/v1/env/diff":{"get":{"summary":"Compare two environments by (app, name) + value fingerprint — only-in-A / only-in-B / differ / same. Values never leave","parameters":[{"name":"environment","in":"query","description":"Environment A"},{"name":"compareTo","in":"query","description":"Environment B"}],"responses":{"200":{"description":"EnvDiff object"},"422":{"description":"Missing/duplicate environments"}}}},"/api/v1/env/{id}":{"get":{"summary":"Env var metadata","responses":{"200":{"description":"Env var"},"404":{"description":"Not found"}}},"delete":{"summary":"Delete env var + version history (write scope)","responses":{"200":{"description":"Deleted"}}}},"/api/v1/env/{id}/reveal":{"post":{"summary":"Reveal plaintext value — audited, rate-limited (60/min/org). Body: { reason? }","responses":{"200":{"description":"{ name, environment, app, value }"},"429":{"description":"Rate limit"}}}},"/api/v1/env/{id}/versions":{"get":{"summary":"Previous values (metadata, newest first, max 20)","responses":{"200":{"description":"Array of versions"}}}},"/api/v1/env/{id}/rollback":{"post":{"summary":"Restore a previous value (write scope). Body: { versionId }","responses":{"200":{"description":"Rolled back"}}}},"/api/v1/integrations":{"get":{"summary":"Stored third-party service keys (metadata only)","responses":{"200":{"description":"Array of integrations"}}},"post":{"summary":"Upsert a service key: { service, label, secret, meta? } (write scope)","responses":{"201":{"description":"Saved"}}}},"/api/v1/integrations/catalog":{"get":{"summary":"Services ServersWallet can store & live-verify keys for","responses":{"200":{"description":"Array of service definitions"}}}},"/api/v1/integrations/{id}":{"delete":{"summary":"Delete a service key (write scope)","responses":{"200":{"description":"Deleted"}}}},"/api/v1/integrations/{id}/reveal":{"post":{"summary":"Plaintext service key — audited, rate-limited. Body: { reason? }","responses":{"200":{"description":"{ service, label, value }"}}}},"/api/v1/integrations/{id}/verify":{"post":{"summary":"Live-check the key against the vendor API (result stored, never the key)","responses":{"200":{"description":"{ ok, message }"}}}},"/api/mcp":{"post":{"summary":"MCP server (JSON-RPC 2.0): initialize, tools/list, tools/call — 14 tools, same auth as REST","responses":{"200":{"description":"JSON-RPC reply"},"202":{"description":"Notification accepted"},"401":{"description":"JSON-RPC error -32001"}}}},"/api/v1/audit":{"get":{"summary":"Recent audit log entries","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"Array of log entries"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key: Authorization: Bearer sw_…"},"cookieAuth":{"type":"apiKey","in":"cookie","name":"sw_session"}}}}