{"openapi":"3.1.0","info":{"title":"Submo Agent API","version":"1.0.0","description":"Public, agent-ready API for Submo. Research endpoints need no key (60 requests / minute / IP). Account, discovery, and cancellation require a paid membership API key (120 / minute). Docs: https://submoapp.com/developers. Auth walkthrough: https://submoapp.com/auth.md. Scans are async: POST returns 202, then poll GET /v1/scans/{id} until status is complete. Every failure — including an unmatched path — returns JSON in the Error shape: { error: { code, message, hint, docs_url } }. Branch on code, not on message. This API never cancels at the provider: it returns steps. Submo does offer a paid done-for-you cancellation notice, but only as a website flow at https://submoapp.com/cancel-subscription.","contact":{"name":"Submo","email":"hello@submoapp.com","url":"https://submoapp.com/developers"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://api.submoapp.com","description":"Submo API"},{"url":"https://submoapp.com","description":"Website proxy of /v1"}],"tags":[{"name":"Research"},{"name":"Checkout"},{"name":"Account"},{"name":"Subscriptions"},{"name":"Discovery"},{"name":"Advisor"}],"externalDocs":{"description":"Agent developer portal","url":"https://submoapp.com/developers"},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"submo_live_…","description":"API key from /developers, agent checkout, or OAuth (authorization_code + PKCE S256). Scopes: research, checkout, account:read, subscriptions:read, subscriptions:write, discovery, advisor"}},"schemas":{"Error":{"type":"object","title":"Error","description":"Every 4xx and 5xx response on this API has this shape. `code` is stable and machine-readable, `hint` says what to do next, and `docs_url` points at the page that explains it.","required":["error"],"properties":{"error":{"type":"object","required":["code","message","hint","docs_url"],"properties":{"code":{"type":"string","description":"Stable machine-readable failure code. Branch on this, not on the message.","enum":["unauthorized","forbidden","not_found","validation_error","rate_limited","payment_required","conflict","not_configured","payload_too_large","internal_error"]},"message":{"type":"string","example":"Subscription not found"},"hint":{"type":"string","description":"How to resolve this failure.","example":"Check the path and any id against the OpenAPI description. Reuse ids returned by earlier calls rather than constructing them."},"docs_url":{"type":"string","format":"uri","description":"Documentation for this failure.","example":"https://submoapp.com/auth.md"},"details":{"description":"Per-failure context — for validation errors, the offending fields."},"retry_after_seconds":{"type":"integer","example":12}}}},"examples":[{"error":{"code":"unauthorized","message":"Missing or invalid API key.","hint":"Send Authorization: Bearer submo_live_… . Get a key from agent checkout (POST /v1/checkout/sessions) or the OAuth authorization_code + PKCE flow.","docs_url":"https://submoapp.com/auth.md"}}]},"Plan":{"type":"object","required":["id","name","currency","intro_amount","standard_amount"],"properties":{"id":{"type":"string","enum":["weekly","monthly","quarterly","yearly"]},"name":{"type":"string","example":"Weekly"},"currency":{"type":"string","example":"usd"},"intro_amount":{"type":"number","example":0.99},"standard_amount":{"type":"number","example":4.99},"interval":{"type":"string","enum":["week","month","year"]},"intro_days":{"type":"integer","example":3},"interval_count":{"type":"integer","example":1},"intro_label":{"type":"string"},"per_label":{"type":"string"},"badge":{"type":"string","nullable":true},"subline":{"type":"string","nullable":true}}},"Subscription":{"type":"object","required":["id","service_name","billing_cycle","status"],"properties":{"id":{"type":"string","format":"uuid"},"service_name":{"type":"string","example":"Netflix"},"logo_url":{"type":"string","format":"uri","nullable":true},"plan_name":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true},"payment_method_label":{"type":"string","nullable":true},"source":{"type":"string","enum":["email","statement","bank","manual","browse-list"]},"status":{"type":"string","enum":["active","pending_cancellation","cancelled"]},"website_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"CancelGuide":{"type":"object","properties":{"slug":{"type":"string","example":"netflix"},"name":{"type":"string","example":"Netflix"},"steps":{"type":"array","items":{"type":"string"}},"url":{"type":"string","format":"uri","nullable":true},"notes":{"type":"array","items":{"type":"string"}}}},"Scan":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","complete","failed"]},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"items":{"type":"array","items":{"type":"object"}}}}},"responses":{"ValidationError":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"PaymentRequired":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"InternalError":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/plans":{"get":{"operationId":"listPlans","summary":"List Submo membership plans","description":"List Submo membership plans","tags":["Research"],"responses":{"200":{"description":"Plans","content":{"application/json":{"schema":{"type":"object","properties":{"plans":{"type":"array","items":{"type":"object","required":["id","name","currency","intro_amount","standard_amount"],"properties":{"id":{"type":"string","enum":["weekly","monthly","quarterly","yearly"]},"name":{"type":"string","example":"Weekly"},"currency":{"type":"string","example":"usd"},"intro_amount":{"type":"number","example":0.99},"standard_amount":{"type":"number","example":4.99},"interval":{"type":"string","enum":["week","month","year"]},"intro_days":{"type":"integer","example":3},"interval_count":{"type":"integer","example":1},"intro_label":{"type":"string"},"per_label":{"type":"string"},"badge":{"type":"string","nullable":true},"subline":{"type":"string","nullable":true}}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/cancel-guides":{"get":{"operationId":"listCancelGuides","summary":"List or search cancellation guides","description":"List or search cancellation guides","tags":["Research"],"parameters":[{"name":"q","in":"query","schema":{"type":"string","example":"netflix"}}],"responses":{"200":{"description":"Guides","content":{"application/json":{"schema":{"type":"object","properties":{"guides":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string","example":"netflix"},"name":{"type":"string","example":"Netflix"},"steps":{"type":"array","items":{"type":"string"}},"url":{"type":"string","format":"uri","nullable":true},"notes":{"type":"array","items":{"type":"string"}}}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/cancel-guides/{slug}":{"get":{"operationId":"getCancelGuide","summary":"Get one cancellation guide","description":"Get one cancellation guide","tags":["Research"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","example":"netflix"}}],"responses":{"200":{"description":"Guide","content":{"application/json":{"schema":{"type":"object","properties":{"guide":{"type":"object","properties":{"slug":{"type":"string","example":"netflix"},"name":{"type":"string","example":"Netflix"},"steps":{"type":"array","items":{"type":"string"}},"url":{"type":"string","format":"uri","nullable":true},"notes":{"type":"array","items":{"type":"string"}}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/price-indexes":{"get":{"operationId":"listPriceIndexes","summary":"List sourced price indexes","description":"List sourced price indexes","tags":["Research"],"responses":{"200":{"description":"Indexes","content":{"application/json":{"schema":{"type":"object","properties":{"indexes":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/price-indexes/{slug}":{"get":{"operationId":"getPriceIndex","summary":"Get one price index and current prices","description":"Get one price index and current prices","tags":["Research"],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Index","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/catalog":{"get":{"operationId":"searchCatalog","summary":"Browse popular services to add","description":"Browse popular services to add","tags":["Research"],"parameters":[{"name":"q","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Catalog","content":{"application/json":{"schema":{"type":"object","properties":{"services":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/checkout/sessions":{"post":{"operationId":"createCheckoutSession","summary":"Start hosted Stripe checkout for a new member","description":"Start hosted Stripe checkout for a new member","tags":["Checkout"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","plan_id"],"properties":{"email":{"type":"string","format":"email","example":"alex@example.com"},"plan_id":{"type":"string","enum":["weekly"]}}}}}},"responses":{"201":{"description":"Checkout URL and poll token","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"checkout_url":{"type":"string","format":"uri"},"poll_token":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"poll_url":{"type":"string","format":"uri"},"next_action":{"type":"object"}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/checkout/sessions/{id}":{"get":{"operationId":"getCheckoutSession","summary":"Poll checkout until paid; returns the API key once","description":"Poll checkout until paid; returns the API key once","tags":["Checkout"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"poll_token","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Checkout status","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/me":{"get":{"operationId":"getAccount","summary":"Current account, membership, and connections","description":"Current account, membership, and connections","tags":["Account"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Account","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions":{"get":{"operationId":"listSubscriptions","summary":"List tracked subscriptions","description":"List tracked subscriptions","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["active","pending_cancellation","cancelled"]}},{"name":"upcoming_before","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"subscriptions":{"type":"array","items":{"type":"object","required":["id","service_name","billing_cycle","status"],"properties":{"id":{"type":"string","format":"uuid"},"service_name":{"type":"string","example":"Netflix"},"logo_url":{"type":"string","format":"uri","nullable":true},"plan_name":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true},"payment_method_label":{"type":"string","nullable":true},"source":{"type":"string","enum":["email","statement","bank","manual","browse-list"]},"status":{"type":"string","enum":["active","pending_cancellation","cancelled"]},"website_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createSubscription","summary":"Add a subscription","description":"Add a subscription","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["service_name","price","currency","billing_cycle"],"properties":{"service_name":{"type":"string","example":"Netflix"},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time"},"website_url":{"type":"string","format":"uri"},"source":{"type":"string","enum":["manual"]}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","required":["id","service_name","billing_cycle","status"],"properties":{"id":{"type":"string","format":"uuid"},"service_name":{"type":"string","example":"Netflix"},"logo_url":{"type":"string","format":"uri","nullable":true},"plan_name":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true},"payment_method_label":{"type":"string","nullable":true},"source":{"type":"string","enum":["email","statement","bank","manual","browse-list"]},"status":{"type":"string","enum":["active","pending_cancellation","cancelled"]},"website_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}":{"get":{"operationId":"getSubscription","summary":"Get one subscription","description":"Get one subscription","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Subscription","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","required":["id","service_name","billing_cycle","status"],"properties":{"id":{"type":"string","format":"uuid"},"service_name":{"type":"string","example":"Netflix"},"logo_url":{"type":"string","format":"uri","nullable":true},"plan_name":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true},"payment_method_label":{"type":"string","nullable":true},"source":{"type":"string","enum":["email","statement","bank","manual","browse-list"]},"status":{"type":"string","enum":["active","pending_cancellation","cancelled"]},"website_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"updateSubscription","summary":"Update a subscription","description":"Update a subscription","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","required":["id","service_name","billing_cycle","status"],"properties":{"id":{"type":"string","format":"uuid"},"service_name":{"type":"string","example":"Netflix"},"logo_url":{"type":"string","format":"uri","nullable":true},"plan_name":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true},"payment_method_label":{"type":"string","nullable":true},"source":{"type":"string","enum":["email","statement","bank","manual","browse-list"]},"status":{"type":"string","enum":["active","pending_cancellation","cancelled"]},"website_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}/cancel":{"post":{"operationId":"cancelSubscription","summary":"Record that the user cancelled with the provider","description":"Record that the user cancelled with the provider","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cancelled plus matching guide","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}/reactivate":{"post":{"operationId":"reactivateSubscription","summary":"Mark a cancelled subscription active again","description":"Mark a cancelled subscription active again","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Reactivated","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","required":["id","service_name","billing_cycle","status"],"properties":{"id":{"type":"string","format":"uuid"},"service_name":{"type":"string","example":"Netflix"},"logo_url":{"type":"string","format":"uri","nullable":true},"plan_name":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true},"payment_method_label":{"type":"string","nullable":true},"source":{"type":"string","enum":["email","statement","bank","manual","browse-list"]},"status":{"type":"string","enum":["active","pending_cancellation","cancelled"]},"website_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/subscriptions/{id}/cancel-guide":{"get":{"operationId":"getSubscriptionCancelGuide","summary":"Cancel steps for a saved subscription","description":"Cancel steps for a saved subscription","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Guide","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/upcoming":{"get":{"operationId":"listUpcomingCharges","summary":"Upcoming renewals","description":"Upcoming renewals","tags":["Subscriptions"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":30,"minimum":1,"maximum":366}}],"responses":{"200":{"description":"Charges","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/connections":{"get":{"operationId":"listConnections","summary":"Email and bank connections (no tokens)","description":"Email and bank connections (no tokens)","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Connections","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/connections/email/start":{"post":{"operationId":"startEmailConnect","summary":"Return a Gmail connect URL for the user","description":"Return a Gmail connect URL for the user","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Connect URL","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/connections/bank/start":{"post":{"operationId":"startBankConnect","summary":"Return a bank connect URL, or statement fallback","description":"Return a bank connect URL, or statement fallback","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Connect URL or alternative","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/scans/email":{"post":{"operationId":"startEmailScan","summary":"Scan the connected Gmail inbox","description":"Scan the connected Gmail inbox","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"responses":{"202":{"description":"Scan started. Poll GET /v1/scans/{id}.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","complete","failed"]},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"items":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/scans/statement":{"post":{"operationId":"uploadStatement","summary":"Parse a bank statement PDF in memory","description":"Parse a bank statement PDF in memory","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pdf_base64"],"properties":{"pdf_base64":{"type":"string","description":"Raw PDF bytes, base64-encoded"},"filename":{"type":"string","example":"statement.pdf"}}}}}},"responses":{"202":{"description":"Scan started. Poll GET /v1/scans/{id}.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","complete","failed"]},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"items":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/scans/latest":{"get":{"operationId":"getLatestScan","summary":"Latest discovery scan","description":"Latest discovery scan","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Scan","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","complete","failed"]},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"items":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/scans/{id}":{"get":{"operationId":"getScan","summary":"One discovery scan","description":"One discovery scan","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Scan","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","running","complete","failed"]},"source":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"items":{"type":"array","items":{"type":"object"}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/scans/{id}/import":{"post":{"operationId":"importScanResults","summary":"Import found subscriptions from a completed scan","description":"Import found subscriptions from a completed scan","tags":["Discovery"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Imported","content":{"application/json":{"schema":{"type":"object","properties":{"subscriptions":{"type":"array","items":{"type":"object","required":["id","service_name","billing_cycle","status"],"properties":{"id":{"type":"string","format":"uuid"},"service_name":{"type":"string","example":"Netflix"},"logo_url":{"type":"string","format":"uri","nullable":true},"plan_name":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":15.49},"currency":{"type":"string","nullable":true,"example":"USD"},"billing_cycle":{"type":"string","enum":["weekly","monthly","yearly"]},"next_payment_date":{"type":"string","format":"date-time","nullable":true},"started_at":{"type":"string","format":"date-time","nullable":true},"payment_method_label":{"type":"string","nullable":true},"source":{"type":"string","enum":["email","statement","bank","manual","browse-list"]},"status":{"type":"string","enum":["active","pending_cancellation","cancelled"]},"website_url":{"type":"string","format":"uri","nullable":true},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/export":{"get":{"operationId":"exportSubscriptions","summary":"Download subscriptions as CSV","description":"Download subscriptions as CSV","tags":["Account"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"CSV","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/advisor/chat":{"post":{"operationId":"advisorChat","summary":"Ask the entitlement-gated subscription advisor","description":"Ask the entitlement-gated subscription advisor","tags":["Advisor"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"Reply","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Validation error. `details` names the offending fields.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"WWW-Authenticate":{"description":"Bearer challenge carrying resource_metadata for OAuth discovery.","schema":{"type":"string"}}}},"402":{"description":"Paid membership required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but is missing the scope this endpoint needs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such route or resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited. Honor Retry-After and X-RateLimit-* headers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"Retry-After":{"schema":{"type":"integer"}},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}}},"500":{"description":"Unexpected server error. Retry once with backoff.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}