{"openapi":"3.1.0","info":{"title":"SSD-MCP Server","version":"2.0.0"},"paths":{"/.well-known/oauth-protected-resource/mcp":{"get":{"summary":"Oauth Protected Resource Metadata","description":"RFC 9728 protected resource metadata for the MCP endpoint.","operationId":"oauth_protected_resource_metadata__well_known_oauth_protected_resource_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"summary":"Oauth Authorization Server Metadata","description":"Proxy Supabase OAuth authorization server metadata.","operationId":"oauth_authorization_server_metadata__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/x402":{"get":{"summary":"Well Known X402","description":"x402 payment discovery (x402scan / IETF draft-jeftovic convention).\n\nCrawlers (x402scan, x402-discovery-mcp) fetch this to auto-register\nx402-enabled resources. The ``instructions`` field is LLM-consumable.","operationId":"well_known_x402__well_known_x402_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/public-mcp-contract-v1.json":{"get":{"summary":"Public Mcp Contract","description":"Serve the generated public contract byte-for-byte, never reserialized.","operationId":"public_mcp_contract_api_public_mcp_contract_v1_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/public-mcp-contract-v1.json":{"get":{"summary":"Public Mcp Contract","description":"Serve the generated public contract byte-for-byte, never reserialized.","operationId":"public_mcp_contract__well_known_public_mcp_contract_v1_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/public-mcp-lane-projection-v1.json":{"get":{"summary":"Public Mcp Lane Projection","description":"Expose the live registry lane projection and its canonical hash.","operationId":"public_mcp_lane_projection_api_public_mcp_lane_projection_v1_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/public-mcp-lane-projection-v1.json":{"get":{"summary":"Public Mcp Lane Projection","description":"Expose the live registry lane projection and its canonical hash.","operationId":"public_mcp_lane_projection__well_known_public_mcp_lane_projection_v1_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/mcp.json":{"get":{"summary":"Well Known Mcp","description":"MCP server discovery (emerging convention, MCP spec discussion #1147).\n\nEnables MCP directories and clients to discover this server's\nendpoint, transport, and capabilities without connecting first.","operationId":"well_known_mcp__well_known_mcp_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/agent.json":{"get":{"summary":"Well Known Agent Card","description":"Google A2A agent card for agent-to-agent discovery.\n\nFollows the Agent2Agent protocol spec (v0.2+). Soundside is not a\nfull A2A server (no JSON-RPC task management), but the agent card\nenables discovery by A2A-aware clients and registries.\n``protocol: mcp`` signals callers to connect via MCP, not A2A.","operationId":"well_known_agent_card__well_known_agent_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/healthz":{"get":{"summary":"Healthz","operationId":"healthz_healthz_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/health":{"get":{"summary":"Api Health","operationId":"api_health_api_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/llms.txt":{"get":{"summary":"Llms Txt","description":"Redirect to canonical llms.txt on the docs site.","operationId":"llms_txt_api_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/llms.txt":{"get":{"summary":"Llms Txt","description":"Redirect to canonical llms.txt on the docs site.","operationId":"llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/x402/status":{"get":{"summary":"X402 Status","description":"Public endpoint — no auth required.\n\nReturns the current x402 payment lane configuration including enabled\ntools with USDC prices. Agents can query this to discover pricing\nwithout hard-coding it.","operationId":"x402_status_api_x402_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/resolve/{resource_id}":{"get":{"summary":"Resolve Resource","description":"Resolve a resource ID to a signed download URL.\n\nUsed by the frontend short-URL redirect route (/r/{shortId}).\n- Public resources: no auth required, returns signed URL.\n- Private resources: requires Authorization header with Supabase JWT\n  or API key. Returns 401 if missing, 403 if user is not authorized.","operationId":"resolve_resource_api_resolve__resource_id__get","parameters":[{"name":"resource_id","in":"path","required":true,"schema":{"type":"string","title":"Resource Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/provider-input/{token}/{filename}":{"get":{"summary":"Provider Input Redirect","description":"Resolve a provider-input capability token to a fresh signed GCS URL.\n\nMinted by `lib/provider_input_urls.py::mint_provider_input_url` for\nproviders (DashScope/Alibaba, 2026-09-17) whose format validators\nreject a plain signed GCS URL because its path ends in the bare\nresource UUID, with no file extension. `filename` exists purely for\nthose providers' own format sniffing (a trailing .mp4/.mov/.avi/\n.mp3/.wav) — this route ignores its value; the token alone\ndetermines which resource is served.\n\nNo Authorization header is checked: the token itself IS the\ncapability (bearer-capability, same model as\n`lib/x402_wallet.py`'s session tokens). `lib_resources.visibility`\nis deliberately NOT consulted here — minting the token already\nrequired the owner-or-public access check (see\n`_resolve_to_provider_url` in\ntoolsets/functional/generation/_common.py); re-deriving or\nnarrowing that decision from a column the token bearer never\ntouched would just be a second, divergent access-control path.\n\nResponses:\n    302 Found, Location: a freshly minted signed GCS URL — the\n        pre-privacy-fix public short-URL flow also redirected and\n        DashScope followed it, so a redirect is proven to work here.\n    400 Bad Request: token is malformed.\n    403 Forbidden: token signature doesn't match (tampered).\n    404 Not Found: token verifies, but the resource doesn't exist,\n        is soft-deleted, or isn't `status='completed'` yet.\n    410 Gone: token verifies but has expired.","operationId":"provider_input_redirect_api_provider_input__token___filename__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"summary":"Provider Input Redirect","description":"Resolve a provider-input capability token to a fresh signed GCS URL.\n\nMinted by `lib/provider_input_urls.py::mint_provider_input_url` for\nproviders (DashScope/Alibaba, 2026-09-17) whose format validators\nreject a plain signed GCS URL because its path ends in the bare\nresource UUID, with no file extension. `filename` exists purely for\nthose providers' own format sniffing (a trailing .mp4/.mov/.avi/\n.mp3/.wav) — this route ignores its value; the token alone\ndetermines which resource is served.\n\nNo Authorization header is checked: the token itself IS the\ncapability (bearer-capability, same model as\n`lib/x402_wallet.py`'s session tokens). `lib_resources.visibility`\nis deliberately NOT consulted here — minting the token already\nrequired the owner-or-public access check (see\n`_resolve_to_provider_url` in\ntoolsets/functional/generation/_common.py); re-deriving or\nnarrowing that decision from a column the token bearer never\ntouched would just be a second, divergent access-control path.\n\nResponses:\n    302 Found, Location: a freshly minted signed GCS URL — the\n        pre-privacy-fix public short-URL flow also redirected and\n        DashScope followed it, so a redirect is proven to work here.\n    400 Bad Request: token is malformed.\n    403 Forbidden: token signature doesn't match (tampered).\n    404 Not Found: token verifies, but the resource doesn't exist,\n        is soft-deleted, or isn't `status='completed'` yet.\n    410 Gone: token verifies but has expired.","operationId":"provider_input_redirect_api_provider_input__token___filename__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}},{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/x402/resource/{resource_id}":{"get":{"summary":"X402 Resource Status","description":"Public polling endpoint for x402 wallet clients.\n\nx402 clients that paid for an async tool call receive a resource_id\nimmediately. They poll this endpoint with the short-lived x402 session\ntoken returned after payment to check status and retrieve the storage URL\nonce the job completes. No payment required.\n\nHeaders:\n    Authorization: Bearer <x402_session_token>\n    or\n    X-Session-Token: <x402_session_token>\n\nReturns:\n    200 with resource metadata (id, name, status, storage_url, mime_type, metadata)\n    404 if resource not found or not owned by the session wallet","operationId":"x402_resource_status_api_x402_resource__resource_id__get","parameters":[{"name":"resource_id","in":"path","required":true,"schema":{"type":"string","title":"Resource Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/x402/resources":{"get":{"summary":"X402 List Resources","description":"List resources owned by an x402 wallet.\n\nWallet clients can browse their library — all resources they've created\nvia x402 pay-per-call. Supports pagination and optional mime_type filter.\n\nHeaders:\n    Authorization: Bearer <x402_session_token>\n    or\n    X-Session-Token: <x402_session_token>\n\nQuery params:\n    limit:      Max resources to return (default 50, max 200)\n    offset:     Pagination offset (default 0)\n    mime_type:  Filter by mime type prefix (e.g. \"image/\", \"video/\", \"audio/\")\n\nReturns:\n    200 with { resources: [...], total: N, limit: N, offset: N }","operationId":"x402_list_resources_api_x402_resources_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/webhooks/adapter-status":{"post":{"summary":"Adapter Training Webhook","description":"Webhook endpoint for Modal training completion callbacks.\n\nCalled by the Modal lora_training app when a training job completes or fails.\nPayload: {job_id, state, adapter_weights_uri, gpu_seconds, gpu_tier, checkpoints, error_message}","operationId":"adapter_training_webhook_webhooks_adapter_status_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/internal/poll":{"post":{"summary":"Internal Poll","description":"Internal endpoint for provider polling (Cloud Tasks wake-ups, WS1 P1.2).\n\nBody ``{\"resource_id\": <uuid>, \"step\": <int, optional>}`` runs one\ndurable poll step (``PersistenceManager.poll_step``); ``step`` is the\nstep a Cloud Tasks task claims, absent on a manual call. Without\nresource_id, processes the next pending resource from the queue.\nAuth: ``lib.internal_auth`` (INTERNAL_POLL_TOKEN or the wake OIDC\ntoken). A step deferred to a revision that has the provider handler\nanswers 503, so Cloud Tasks retries it.","operationId":"internal_poll_internal_poll_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/internal/resume-compositions":{"post":{"summary":"Internal Resume Compositions","description":"Compose finisher for out-of-process resume. Drains the outbox,\nreconciles the slot and takes over the expired parent, then detaches its\nrecovery (under the claim's JobIdentity, so SIGTERM shortens its lease)\nand returns once the claim is made, as /internal/resume-remixes does\n(WS6 M1: a recovery waiting on pending provider work can hold its lease\nfor up to 30 min, longer than any request). Intended to be hit by Cloud\nScheduler.\n\nAuth: same Bearer token as /internal/poll (INTERNAL_POLL_TOKEN).\nFeature flag: same as /internal/poll (ENABLE_INTERNAL_POLL_ENDPOINT).\n\nBody (optional): {\"limit\": 1-10} — max compositions to claim this call.\n\nUnder PRODUCTION_RUNNER=job (WS1 P2.3, C2) it drains the outbox and\nreconciles the slot as before, but the takeover launches a job\n(``lib.job_launch.job_mode_compose_sweep``) instead of finishing here.","operationId":"internal_resume_compositions_internal_resume_compositions_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/internal/resume-remixes":{"post":{"summary":"Internal Resume Remixes","description":"Request-held remix finisher — the owner-triggered counterpart to\n/internal/resume-compositions, for remix parents whose lease expired\n(a crashed or evicted instance, or a phase that outran its lease).\nClaims each expired per-user remix slot and restarts the phase walk\nfrom the durable checkpoint. Unlike the compose finisher this does\nNOT await the walk: a remix job runs for many minutes, so each\nresumed run is detached (kept alive by its own lease heartbeat) and\nthis returns as soon as the claims are made. The caller sees\ncompletion through `lib_list` (WS1 P2.6: no standalone push stream\non the request-billed front door).\n\nAuth: same Bearer token as /internal/poll (INTERNAL_POLL_TOKEN).\nFeature flag: same as /internal/poll (ENABLE_INTERNAL_POLL_ENDPOINT).\n\nBody (optional): {\"limit\": 1-10} — max remix jobs to claim this call.\n\nUnder PRODUCTION_RUNNER=job (WS1 P2.3, C2) each expired slot is taken\nover and launched as a job (``lib.job_launch.job_mode_remix_sweep``);\nnothing is resumed in this process.","operationId":"internal_resume_remixes_internal_resume_remixes_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/internal/lease-watchdog":{"post":{"summary":"Internal Lease Watchdog","description":"Lease-expiry check for a production job (WS1 P1.3; a Cloud Tasks wake-up).\n\nBody ``{\"kind\", \"parent_id\", \"fence\", \"n\"}``. Reads the job's slot and\nparent and writes no durable state: stops (200) when the job is\nterminal, unbound or under another fence; spawns the kind's existing\nfenced resume (202) when the lease expired; re-arms itself while the\njob is pending under the same fence (``lib.lease_watchdog``).\nUnder PRODUCTION_RUNNER=job (WS1 P2.3, C2) an expired lease is taken\nover inline and launched as a job (``lib.job_launch``), never resumed\nhere. Auth: ``lib.internal_auth``. Feature flag:\nENABLE_INTERNAL_POLL_ENDPOINT.","operationId":"internal_lease_watchdog_internal_lease_watchdog_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/internal/launch-job":{"post":{"summary":"Internal Launch Job","description":"Launch the Cloud Run Job execution for a handed-over parent (WS1 P2.3;\nthe Cloud Tasks task ``launch-<parent>-<fence>``).\n\nBody ``{\"kind\", \"parent_id\", \"fence\"}``. Reads the parent and its slot\nand launches only while the slot holds that fence's live, unclaimed\nhandoff marker; otherwise 200 ``superseded``. ``jobs.run`` success ->\n200 with the execution; a definitive error (PERMISSION_DENIED,\nNOT_FOUND, INVALID_ARGUMENT) fails the parent closed and answers 200;\na transient error answers 503 so Cloud Tasks retries\n(``lib.job_launch.run_launch_request``). Exists only under\nPRODUCTION_RUNNER=job (404 otherwise). Auth: ``lib.internal_auth``.\nFeature flag: ENABLE_INTERNAL_POLL_ENDPOINT.","operationId":"internal_launch_job_internal_launch_job_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/internal/notify":{"post":{"summary":"Internal Notify","description":"Push ``notifications/resources/updated`` for a resource a production\njob published (WS1 P2.3). A job has no MCP sessions of its own, so it\ncalls this after publishing and the front door broadcasts to the\nuser's MCP sessions (``utils.session_registry``).\n\nThe push is best-effort (WS1 P2.6): it reaches only clients holding a\nstandalone ``GET /mcp`` stream, which this server offers only with\n``MCP_STANDALONE_SSE=on``. This route has no web leg: the web learns of\nthe change from the outbox delivery's Next.js POST\n(``utils.notifications.deliver_resource_notification_strict``), and\nevery client can read it with ``lib_list``.\n\nBody ``{\"resource_id\", \"user_id\"}``; the resource must belong to the\nuser (404 otherwise). Read-only besides the broadcast. Exists only\nunder PRODUCTION_RUNNER=job (404 otherwise). Auth:\n``lib.internal_auth``. Feature flag: ENABLE_INTERNAL_POLL_ENDPOINT.","operationId":"internal_notify_internal_notify_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}