{"openapi":"3.1.0","info":{"title":"CredWatch Portal","version":"0.1.0"},"paths":{"/reset-password":{"get":{"tags":["reset_password"],"summary":"Reset Password Page","operationId":"reset_password_page_reset_password_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["reset_password"],"summary":"Reset Password Request","operationId":"reset_password_request_reset_password_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_reset_password_request_reset_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reset-password/confirm":{"get":{"tags":["reset_password"],"summary":"Reset Password Confirm Page","operationId":"reset_password_confirm_page_reset_password_confirm_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["reset_password"],"summary":"Reset Password Confirm","operationId":"reset_password_confirm_reset_password_confirm_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_reset_password_confirm_reset_password_confirm_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing":{"get":{"tags":["billing"],"summary":"Billing Page","operationId":"billing_page_billing_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout","description":"Create a Stripe Checkout Session and redirect the user to it.","operationId":"create_checkout_billing_checkout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/billing/success":{"get":{"tags":["billing"],"summary":"Checkout Success","description":"Post-checkout landing page.\n\nThe webhook (checkout.session.completed) is the primary mechanism for\napplying the plan upgrade, but there's a race: Stripe redirects the user\nhere *before* the webhook fires.  To guarantee the plan is applied and the\ncorrect plan name is shown in the confirmation message we:\n\n  1. Retrieve the checkout session from Stripe using the session_id query\n     param (always present in the success_url).\n  2. Extract the plan from the session's metadata.\n  3. If the webhook has already fired, client.plan already matches — no-op.\n     If not, apply the plan now (idempotent — same logic as the webhook).\n  4. Pass the purchased plan name to the template so the message is always\n     correct regardless of webhook timing.","operationId":"checkout_success_billing_success_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/billing/cancel":{"get":{"tags":["billing"],"summary":"Checkout Cancel","operationId":"checkout_cancel_billing_cancel_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/billing/portal":{"post":{"tags":["billing"],"summary":"Customer Portal","description":"Redirect the client to the Stripe Customer Portal (manage/cancel subscription).","operationId":"customer_portal_billing_portal_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/billing/webhook":{"post":{"tags":["billing"],"summary":"Stripe Webhook","description":"Stripe sends signed webhook events here.  Verify signature before\ntrusting any payload — Stripe-Signature header + webhook secret.\n\nHandled events:\n  checkout.session.completed    — new subscription created, upgrade plan\n  customer.subscription.updated — plan changed (upgrade/downgrade via portal)\n  customer.subscription.deleted — subscription cancelled, downgrade to free\n  invoice.payment_failed        — log warning; grace period handled by Stripe","operationId":"stripe_webhook_billing_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/login":{"get":{"tags":["auth"],"summary":"Login Page","operationId":"login_page_login_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["auth"],"summary":"Login Submit","operationId":"login_submit_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_submit_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/login/mfa":{"get":{"tags":["auth"],"summary":"Mfa Page","operationId":"mfa_page_login_mfa_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["auth"],"summary":"Mfa Submit","operationId":"mfa_submit_login_mfa_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_mfa_submit_login_mfa_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/logout":{"get":{"tags":["auth"],"summary":"Logout","operationId":"logout_logout_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/signup":{"get":{"tags":["signup"],"summary":"Signup Page","operationId":"signup_page_signup_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["signup"],"summary":"Signup Submit","operationId":"signup_submit_signup_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_signup_submit_signup_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/verify-email":{"get":{"tags":["signup"],"summary":"Verify Email","operationId":"verify_email_verify_email_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/resend-verification":{"get":{"tags":["signup"],"summary":"Resend Verification","operationId":"resend_verification_resend_verification_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/dashboard":{"get":{"tags":["dashboard"],"summary":"Dashboard","operationId":"dashboard_dashboard_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/findings":{"get":{"tags":["findings"],"summary":"Findings List","operationId":"findings_list_findings_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"source_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Type"}},{"name":"validation","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Validation"}},{"name":"pattern_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pattern Id"}},{"name":"tag","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag"}},{"name":"min_score","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Score"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date To"}},{"name":"days","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Days"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"first_seen_at","title":"Sort"}},{"name":"dir","in":"query","required":false,"schema":{"type":"string","default":"desc","title":"Dir"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/export":{"get":{"tags":["findings"],"summary":"Export Findings","description":"Stream all findings that match the current filter state as a CSV or JSON\nfile download.  No pagination — exports the full result set (capped at\n50,000 rows to prevent accidental runaway queries).\n\nThe export deliberately omits internal fields (fingerprint, secret_hash,\nclient_id, validation_detail JSONB, resolution_evidence JSONB) so that\nthe file is safe to share with a wider team without exposing raw secrets\nor internal IDs.","operationId":"export_findings_findings_export_get","parameters":[{"name":"fmt","in":"query","required":false,"schema":{"type":"string","default":"csv","title":"Fmt"}},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Q"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"source_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Type"}},{"name":"validation","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Validation"}},{"name":"pattern_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pattern Id"}},{"name":"min_score","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Min Score"}},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date From"}},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Date To"}},{"name":"days","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}":{"get":{"tags":["findings"],"summary":"Finding Detail","operationId":"finding_detail_findings__finding_id__get","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/resolve":{"post":{"tags":["findings"],"summary":"Resolve Finding","operationId":"resolve_finding_findings__finding_id__resolve_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_resolve_finding_findings__finding_id__resolve_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/fp":{"post":{"tags":["findings"],"summary":"False Positive Finding","operationId":"false_positive_finding_findings__finding_id__fp_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_false_positive_finding_findings__finding_id__fp_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/restrict":{"post":{"tags":["findings"],"summary":"Restrict Finding","description":"Mark a finding `customer_restricted` — the credential is real and\nexposed but the customer has scoped / IP-restricted / disabled it so\nit can't be exploited as-found.  Until this route shipped this status\nwas settable only via the CLI (`credwatch findings restrict <id>`).","operationId":"restrict_finding_findings__finding_id__restrict_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_restrict_finding_findings__finding_id__restrict_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/reopen":{"post":{"tags":["findings"],"summary":"Reopen Finding","description":"Reopen a resolved or false-positive finding back to active.\nClears resolved_at, resolution_note, and suppressed flag.","operationId":"reopen_finding_findings__finding_id__reopen_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/name":{"post":{"tags":["findings"],"summary":"Set Credential Name","description":"Assign (or update) a human-readable name for the credential referenced\nby this finding.  The name is keyed on (client_id, secret_hash) so it\npropagates automatically to all sibling findings that share the same\nleaked credential.\n\nSubmitting an empty name clears the existing label.","operationId":"set_credential_name_findings__finding_id__name_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_credential_name_findings__finding_id__name_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/note":{"post":{"tags":["findings"],"summary":"Set Analyst Note","description":"Set or clear the analyst note on a specific finding.\nThe note is per-finding (not per-credential), so different occurrences\nof the same key can have distinct notes.","operationId":"set_analyst_note_findings__finding_id__note_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_analyst_note_findings__finding_id__note_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/tags":{"post":{"tags":["findings"],"summary":"Set Tags","description":"Replace the finding's tag list.\n\n``tags_raw`` is a comma-separated string from the text input, e.g.\n\"prod, high-priority, needs-rotation\".  Tags are lowercased, stripped,\ndeduplicated, and capped at 20 per finding.  Empty submission clears all tags.","operationId":"set_tags_findings__finding_id__tags_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_tags_findings__finding_id__tags_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/recheck":{"post":{"tags":["findings"],"summary":"Recheck Finding","description":"Enqueue an on-demand validation job for this finding.\n\nRe-uses the existing ``validate_finding_job`` RQ job (same path used\nduring normal scan validation).  A Redis key acts as a pending-flag so\nthe button can show a loading/disabled state on the next page load.\n\nRate-limited to one outstanding recheck per finding at a time: if the\nflag key already exists the request is a no-op (idempotent).","operationId":"recheck_finding_findings__finding_id__recheck_post","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/patterns":{"get":{"tags":["patterns"],"summary":"Patterns List","operationId":"patterns_list_patterns_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["patterns"],"summary":"Create Pattern","operationId":"create_pattern_patterns_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_create_pattern_patterns_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/patterns/{pattern_id}/toggle":{"post":{"tags":["patterns"],"summary":"Toggle Pattern","operationId":"toggle_pattern_patterns__pattern_id__toggle_post","parameters":[{"name":"pattern_id","in":"path","required":true,"schema":{"type":"string","title":"Pattern Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/patterns/{pattern_id}/edit":{"post":{"tags":["patterns"],"summary":"Edit Pattern","operationId":"edit_pattern_patterns__pattern_id__edit_post","parameters":[{"name":"pattern_id","in":"path","required":true,"schema":{"type":"string","title":"Pattern Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_edit_pattern_patterns__pattern_id__edit_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/patterns/{pattern_id}/delete":{"post":{"tags":["patterns"],"summary":"Delete Pattern","operationId":"delete_pattern_patterns__pattern_id__delete_post","parameters":[{"name":"pattern_id","in":"path","required":true,"schema":{"type":"string","title":"Pattern Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/domains":{"get":{"tags":["domains"],"summary":"Domains List","operationId":"domains_list_domains_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/domains/add":{"post":{"tags":["domains"],"summary":"Add Domain","operationId":"add_domain_domains_add_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_add_domain_domains_add_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/domains/upload":{"post":{"tags":["domains"],"summary":"Upload Domains","description":"Accept a CSV file with domains separated by commas.\nMultiple rows are supported; spaces around commas are ignored.\nDuplicates and invalid entries are silently skipped.\n\nExample formats accepted:\n    domain1.com, domain2.com, domain3.com\n    domain1.com,domain2.com\n    domain1.com, domain2.com\n    domain3.com, domain4.com","operationId":"upload_domains_domains_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_domains_domains_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/domains/{dv_id}/verify":{"post":{"tags":["domains"],"summary":"Verify Domain","operationId":"verify_domain_domains__dv_id__verify_post","parameters":[{"name":"dv_id","in":"path","required":true,"schema":{"type":"string","title":"Dv Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_verify_domain_domains__dv_id__verify_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/domains/{dv_id}/remove":{"post":{"tags":["domains"],"summary":"Remove Domain","operationId":"remove_domain_domains__dv_id__remove_post","parameters":[{"name":"dv_id","in":"path","required":true,"schema":{"type":"string","title":"Dv Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/github":{"get":{"tags":["github"],"summary":"Github Overview","operationId":"github_overview_github_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/github/orgs/add":{"post":{"tags":["github"],"summary":"Add Org","operationId":"add_org_github_orgs_add_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_add_org_github_orgs_add_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/github/orgs/{org}/remove":{"post":{"tags":["github"],"summary":"Remove Org","operationId":"remove_org_github_orgs__org__remove_post","parameters":[{"name":"org","in":"path","required":true,"schema":{"type":"string","title":"Org"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/github/users/add":{"post":{"tags":["github"],"summary":"Add User","operationId":"add_user_github_users_add_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_add_user_github_users_add_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/github/users/{user}/remove":{"post":{"tags":["github"],"summary":"Remove User","operationId":"remove_user_github_users__user__remove_post","parameters":[{"name":"user","in":"path","required":true,"schema":{"type":"string","title":"User"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/github/token/save":{"post":{"tags":["github"],"summary":"Save Private Token","description":"Store an encrypted per-client GitHub PAT for private repo scanning.","operationId":"save_private_token_github_token_save_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_save_private_token_github_token_save_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/github/token/clear":{"post":{"tags":["github"],"summary":"Clear Private Token","description":"Remove the stored per-client GitHub PAT.","operationId":"clear_private_token_github_token_clear_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/github/repos/enumerate":{"post":{"tags":["github"],"summary":"Enumerate Repos","description":"Enumerate all repositories the client's GitHub token can access and\nupsert them into monitored_repos.  Called by the \"Refresh\" button.\n\nIf the total number of repos discovered is ≤ plan_repos_limit, all\nrepos are automatically enabled so the client doesn't have to do\nanything to get scanning working.\n\nExisting rows are preserved — calling this again after adding a new\norg won't reset enabled/wiped_at on repos the client already configured.","operationId":"enumerate_repos_github_repos_enumerate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/github/repos/{repo_id}/enable":{"post":{"tags":["github"],"summary":"Enable Repo","description":"Enable a monitored repo for scanning. Returns JSON.","operationId":"enable_repo_github_repos__repo_id__enable_post","parameters":[{"name":"repo_id","in":"path","required":true,"schema":{"type":"integer","title":"Repo Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/github/repos/{repo_id}/disable":{"post":{"tags":["github"],"summary":"Disable Repo","description":"Disable a monitored repo.\n\nWipe policy: if the client is AT their plan_repos_limit at the time of\nthis request, all findings and scan history for this repo are deleted\nbefore disabling.  This prevents free-tier exploitation by repo rotation.\n\nIf the client is below their limit, data is kept (the slot is already free).\n\nReturns JSON with {ok, enabled, wiped, wipe_stats}.","operationId":"disable_repo_github_repos__repo_id__disable_post","parameters":[{"name":"repo_id","in":"path","required":true,"schema":{"type":"integer","title":"Repo Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/live":{"get":{"tags":["scans"],"summary":"Scan Live","description":"Returns current in-progress scan state for the progress widget.","operationId":"scan_live_scans_live_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/scans":{"get":{"tags":["scans"],"summary":"Scans List","operationId":"scans_list_scans_get","parameters":[{"name":"scan_page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Scan Page"}},{"name":"scrape_page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Scrape Page"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/github/trigger":{"post":{"tags":["scans"],"summary":"Trigger Github Scan","description":"Manually trigger a full GitHub scan for the logged-in client.\n\nReturns 409 if a scan is already in progress — this is the server-side\nguard that backs up the disabled-button UI.  Clients calling the API\ndirectly get the same rejection.\n\nPre-creates a ScanRun row before enqueuing so the progress card on /scans\nappears immediately on the next page load rather than waiting for the worker\nto dequeue the job and start the scanner.","operationId":"trigger_github_scan_scans_github_trigger_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/scans/scrape/trigger":{"post":{"tags":["scans"],"summary":"Trigger Scrape","description":"Manually trigger a full web scrape for the logged-in client.\n\nSame server-side guard and pre-creation pattern as the GitHub trigger.","operationId":"trigger_scrape_scans_scrape_trigger_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/scans/scrape/live":{"get":{"tags":["scans"],"summary":"Scrape Live","description":"Returns current in-progress scrape state for the progress widget.","operationId":"scrape_live_scans_scrape_live_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/scans/github/{run_id}":{"get":{"tags":["scans"],"summary":"Scan Detail","operationId":"scan_detail_scans_github__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/scrape/{run_id}":{"get":{"tags":["scans"],"summary":"Scrape Detail","operationId":"scrape_detail_scans_scrape__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/commit-history":{"get":{"tags":["scans"],"summary":"Commit History Detail","operationId":"commit_history_detail_scans_commit_history_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/scans/commit-history/trigger":{"post":{"tags":["scans"],"summary":"Trigger Commit History","description":"Enqueue commit-history scan jobs for all repos the client has access to.\nUses the client's GitHub PAT to enumerate repos then submits one RQ job\nper repo to the commit_history queue.","operationId":"trigger_commit_history_scans_commit_history_trigger_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/scans/scrape/target/{target_id}/check":{"post":{"tags":["scans"],"summary":"Check Target Liveness","description":"Enqueue a liveness probe for a single scrape target.","operationId":"check_target_liveness_scans_scrape_target__target_id__check_post","parameters":[{"name":"target_id","in":"path","required":true,"schema":{"type":"string","title":"Target Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/scrape/target/{target_id}/rescan":{"post":{"tags":["scans"],"summary":"Rescan Target","description":"Enqueue a full crawl + detect cycle for a single scrape target.\n\nrun_id (query param) — the ScrapeRun the user is currently viewing.\nWhen provided the job writes a scrape_run_targets row so the re-scanned\ntarget stays anchored to this run's detail page.","operationId":"rescan_target_scans_scrape_target__target_id__rescan_post","parameters":[{"name":"target_id","in":"path","required":true,"schema":{"type":"string","title":"Target Id"}},{"name":"run_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports":{"get":{"tags":["reports"],"summary":"Reports Dashboard","operationId":"reports_dashboard_reports_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/reports/export/csv":{"get":{"tags":["reports"],"summary":"Export Csv","operationId":"export_csv_reports_export_csv_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/profile":{"get":{"tags":["profile"],"summary":"Profile Page","operationId":"profile_page_profile_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/profile/password":{"post":{"tags":["profile"],"summary":"Change Password","operationId":"change_password_profile_password_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_change_password_profile_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profile/email":{"post":{"tags":["profile"],"summary":"Update Email","description":"Update the contact email for the account.\nThis email can also be used to log in and is sent to Stripe during checkout.","operationId":"update_email_profile_email_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_update_email_profile_email_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profile/mfa/setup":{"get":{"tags":["profile"],"summary":"Mfa Setup Page","description":"Generate a fresh TOTP secret and recovery codes, store them in the session\n(not yet in DB — we wait for the user to confirm their authenticator works),\nthen display a QR code + recovery codes + verification form.\n\nVisiting this page again before verifying regenerates the secret, which is\nintentional: it means the user can restart if they scanned the wrong account.","operationId":"mfa_setup_page_profile_mfa_setup_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/profile/mfa/verify":{"post":{"tags":["profile"],"summary":"Mfa Verify","description":"Verify the TOTP code against the pending secret stored in the session.\nOn success: encrypt secret + recovery codes → DB, set totp_enabled=True.","operationId":"mfa_verify_profile_mfa_verify_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_mfa_verify_profile_mfa_verify_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profile/mfa/disable":{"post":{"tags":["profile"],"summary":"Mfa Disable","description":"Disable MFA.  Requires a current valid TOTP code to prevent an attacker\nwith an unlocked screen from silently downgrading the account's security.","operationId":"mfa_disable_profile_mfa_disable_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_mfa_disable_profile_mfa_disable_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/suppression":{"get":{"tags":["suppression"],"summary":"Suppression List","operationId":"suppression_list_suppression_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"tags":["suppression"],"summary":"Create Rule","operationId":"create_rule_suppression_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_create_rule_suppression_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/suppression/{rule_id}/delete":{"post":{"tags":["suppression"],"summary":"Delete Rule","operationId":"delete_rule_suppression__rule_id__delete_post","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"integer","title":"Rule Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations":{"get":{"tags":["integrations"],"summary":"Integrations Page","operationId":"integrations_page_integrations_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/integrations/notifications/slack":{"post":{"tags":["integrations"],"summary":"Set Slack Webhook","operationId":"set_slack_webhook_integrations_notifications_slack_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_slack_webhook_integrations_notifications_slack_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations/notifications/slack/test":{"post":{"tags":["integrations"],"summary":"Test Slack Webhook","operationId":"test_slack_webhook_integrations_notifications_slack_test_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/integrations/notifications/webhook":{"post":{"tags":["integrations"],"summary":"Set Outbound Webhook","operationId":"set_outbound_webhook_integrations_notifications_webhook_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_outbound_webhook_integrations_notifications_webhook_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations/notifications/pagerduty":{"post":{"tags":["integrations"],"summary":"Set Pagerduty","description":"Save or clear a PagerDuty Events API v2 integration routing key.","operationId":"set_pagerduty_integrations_notifications_pagerduty_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_pagerduty_integrations_notifications_pagerduty_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations/notifications/opsgenie":{"post":{"tags":["integrations"],"summary":"Set Opsgenie","description":"Save or clear an OpsGenie Alerts API key.","operationId":"set_opsgenie_integrations_notifications_opsgenie_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_opsgenie_integrations_notifications_opsgenie_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations/notifications/jira":{"post":{"tags":["integrations"],"summary":"Set Jira","description":"Save or clear Jira Cloud integration credentials.","operationId":"set_jira_integrations_notifications_jira_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_jira_integrations_notifications_jira_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/integrations/notifications/linear":{"post":{"tags":["integrations"],"summary":"Set Linear","description":"Save or clear Linear integration credentials.","operationId":"set_linear_integrations_notifications_linear_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_linear_integrations_notifications_linear_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/":{"get":{"tags":["team"],"summary":"Team Page","operationId":"team_page_team__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/team/invite":{"post":{"tags":["team"],"summary":"Team Invite","operationId":"team_invite_team_invite_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_team_invite_team_invite_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/{user_id}/remove":{"post":{"tags":["team"],"summary":"Team Remove","operationId":"team_remove_team__user_id__remove_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/{user_id}/role":{"post":{"tags":["team"],"summary":"Team Change Role","operationId":"team_change_role_team__user_id__role_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_team_change_role_team__user_id__role_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/":{"get":{"tags":["org"],"summary":"Org Page","operationId":"org_page_org__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/org/audit-log/export":{"get":{"tags":["org"],"summary":"Export Audit Log","description":"CSV export of the audit log honouring the same filters as the table.","operationId":"export_audit_log_org_audit_log_export_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/org/general/scan-interval":{"post":{"tags":["org"],"summary":"Set Scan Interval","operationId":"set_scan_interval_org_general_scan_interval_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_scan_interval_org_general_scan_interval_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/team/invite":{"post":{"tags":["org"],"summary":"Team Invite","operationId":"team_invite_org_team_invite_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_team_invite_org_team_invite_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/team/{user_id}/remove":{"post":{"tags":["org"],"summary":"Team Remove","operationId":"team_remove_org_team__user_id__remove_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/team/{user_id}/role":{"post":{"tags":["org"],"summary":"Team Change Role","operationId":"team_change_role_org_team__user_id__role_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_team_change_role_org_team__user_id__role_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/notifications/email/add":{"post":{"tags":["org"],"summary":"Add Alert Email","operationId":"add_alert_email_org_notifications_email_add_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_add_alert_email_org_notifications_email_add_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/notifications/email/remove":{"post":{"tags":["org"],"summary":"Remove Alert Email","operationId":"remove_alert_email_org_notifications_email_remove_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_remove_alert_email_org_notifications_email_remove_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/security/mfa-enforcement":{"post":{"tags":["org"],"summary":"Set Mfa Enforcement","operationId":"set_mfa_enforcement_org_security_mfa_enforcement_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_set_mfa_enforcement_org_security_mfa_enforcement_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/webhooks/mailjet/{secret}":{"post":{"tags":["webhooks"],"summary":"Mailjet Event","description":"Receive a Mailjet event-API callback and update email_suppression.\n\nMailjet sends events either:\n  - one at a time (top-level object), or\n  - in batches (JSON array of objects), if \"Group events\" is enabled\n    in the trigger configuration.\nBoth shapes are accepted.","operationId":"mailjet_event_webhooks_mailjet__secret__post","parameters":[{"name":"secret","in":"path","required":true,"schema":{"type":"string","title":"Secret"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/findings":{"get":{"tags":["api:findings"],"summary":"List Findings","description":"List findings for your account with optional filters.","operationId":"list_findings_api_v1_findings_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status (active, resolved, false_positive, customer_restricted, stale)","title":"Status"},"description":"Filter by status (active, resolved, false_positive, customer_restricted, stale)"},{"name":"source_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by source type (repo, gist, commit, endpoint, js_bundle)","title":"Source Type"},"description":"Filter by source type (repo, gist, commit, endpoint, js_bundle)"},{"name":"validation","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by validation_status (valid, invalid, unvalidated, error)","title":"Validation"},"description":"Filter by validation_status (valid, invalid, unvalidated, error)"},{"name":"min_score","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":100,"minimum":0},{"type":"null"}],"description":"Minimum composite_score","title":"Min Score"},"description":"Minimum composite_score"},{"name":"date_from","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"First seen on or after (ISO 8601 date, e.g. 2025-01-01)","title":"Date From"},"description":"First seen on or after (ISO 8601 date, e.g. 2025-01-01)"},{"name":"date_to","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"First seen on or before (ISO 8601 date)","title":"Date To"},"description":"First seen on or before (ISO 8601 date)"},{"name":"q","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Full-text search across source_url, file_path, repo_full_name","title":"Q"},"description":"Full-text search across source_url, file_path, repo_full_name"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"description":"Page number (1-based)","default":1,"title":"Page"},"description":"Page number (1-based)"},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"description":"Results per page (max 200)","default":25,"title":"Per Page"},"description":"Results per page (max 200)"},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Sort field: composite_score, first_seen_at, last_seen_at","default":"composite_score","title":"Order By"},"description":"Sort field: composite_score, first_seen_at, last_seen_at"},{"name":"order_dir","in":"query","required":false,"schema":{"type":"string","description":"Sort direction: asc or desc","default":"desc","title":"Order Dir"},"description":"Sort direction: asc or desc"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/findings/{finding_id}":{"get":{"tags":["api:findings"],"summary":"Get Finding","description":"Get a single finding by ID.","operationId":"get_finding_api_v1_findings__finding_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/findings/{finding_id}/suppress":{"post":{"tags":["api:findings"],"summary":"Suppress Finding","description":"Suppress a finding (hide from active view without changing status).","operationId":"suppress_finding_api_v1_findings__finding_id__suppress_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/findings/{finding_id}/resolve":{"post":{"tags":["api:findings"],"summary":"Resolve Finding","description":"Resolve a finding — mark the exposed credential as rotated/removed.","operationId":"resolve_finding_api_v1_findings__finding_id__resolve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}},{"name":"note","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional resolution note (max 500 chars)","title":"Note"},"description":"Optional resolution note (max 500 chars)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/findings/{finding_id}/restrict":{"post":{"tags":["api:findings"],"summary":"Restrict Finding","description":"Mark a finding `customer_restricted` — the credential is real and\nexposed, but the customer has restricted (scope / IP-allowlist / etc.)\nit so it is not exploitable as-found.  The finding is closed but the\noriginal exposure is acknowledged.\n\nIdempotent: re-calling on an already-restricted finding returns the\ncurrent state without rewriting it.","operationId":"restrict_finding_api_v1_findings__finding_id__restrict_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}},{"name":"note","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional restriction note (max 500 chars)","title":"Note"},"description":"Optional restriction note (max 500 chars)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/scans":{"get":{"tags":["api:scans"],"summary":"List Scans","description":"List recent scan runs for your account.","operationId":"list_scans_api_v1_scans_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by scan type: github, scrape","title":"Type"},"description":"Filter by scan type: github, scrape"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of runs to return (max 100)","default":20,"title":"Limit"},"description":"Number of runs to return (max 100)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/scans/{scan_id}":{"get":{"tags":["api:scans"],"summary":"Get Scan","description":"Get a single scan run by ID (GitHub scan or web scrape).","operationId":"get_scan_api_v1_scans__scan_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","title":"Scan Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profile/api-keys/create":{"post":{"tags":["profile"],"summary":"Create Api Key","description":"Generate a new API key and flash the raw value once in the session.","operationId":"create_api_key_profile_api_keys_create_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_create_api_key_profile_api_keys_create_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/profile/api-keys/{key_id}/revoke":{"post":{"tags":["profile"],"summary":"Revoke Api Key","description":"Revoke an API key immediately — any in-flight requests using it will receive 401.","operationId":"revoke_api_key_profile_api_keys__key_id__revoke_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_add_alert_email_org_notifications_email_add_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_add_alert_email_org_notifications_email_add_post"},"Body_add_domain_domains_add_post":{"properties":{"domain":{"type":"string","title":"Domain"}},"type":"object","required":["domain"],"title":"Body_add_domain_domains_add_post"},"Body_add_org_github_orgs_add_post":{"properties":{"org":{"type":"string","title":"Org"}},"type":"object","required":["org"],"title":"Body_add_org_github_orgs_add_post"},"Body_add_user_github_users_add_post":{"properties":{"user":{"type":"string","title":"User"}},"type":"object","required":["user"],"title":"Body_add_user_github_users_add_post"},"Body_change_password_profile_password_post":{"properties":{"current_password":{"type":"string","title":"Current Password"},"new_password":{"type":"string","title":"New Password"},"confirm_password":{"type":"string","title":"Confirm Password"}},"type":"object","required":["current_password","new_password","confirm_password"],"title":"Body_change_password_profile_password_post"},"Body_create_api_key_profile_api_keys_create_post":{"properties":{"name":{"type":"string","title":"Name","default":""}},"type":"object","title":"Body_create_api_key_profile_api_keys_create_post"},"Body_create_pattern_patterns_post":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","title":"Type"},"value":{"type":"string","title":"Value"},"secret_type":{"type":"string","title":"Secret Type","default":""},"confidence":{"type":"string","title":"Confidence","default":"1.0"},"github_searchable":{"type":"string","title":"Github Searchable","default":""}},"type":"object","required":["name","type","value"],"title":"Body_create_pattern_patterns_post"},"Body_create_rule_suppression_post":{"properties":{"pattern_id":{"type":"string","title":"Pattern Id","default":""},"repo_glob":{"type":"string","title":"Repo Glob","default":""},"path_glob":{"type":"string","title":"Path Glob","default":""},"reason":{"type":"string","title":"Reason","default":""}},"type":"object","title":"Body_create_rule_suppression_post"},"Body_edit_pattern_patterns__pattern_id__edit_post":{"properties":{"name":{"type":"string","title":"Name"},"github_searchable":{"type":"string","title":"Github Searchable","default":""}},"type":"object","required":["name"],"title":"Body_edit_pattern_patterns__pattern_id__edit_post"},"Body_false_positive_finding_findings__finding_id__fp_post":{"properties":{"note":{"type":"string","title":"Note","default":""}},"type":"object","title":"Body_false_positive_finding_findings__finding_id__fp_post"},"Body_login_submit_login_post":{"properties":{"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"}},"type":"object","required":["username","password"],"title":"Body_login_submit_login_post"},"Body_mfa_disable_profile_mfa_disable_post":{"properties":{"totp_code":{"type":"string","title":"Totp Code"}},"type":"object","required":["totp_code"],"title":"Body_mfa_disable_profile_mfa_disable_post"},"Body_mfa_submit_login_mfa_post":{"properties":{"code":{"type":"string","title":"Code"}},"type":"object","required":["code"],"title":"Body_mfa_submit_login_mfa_post"},"Body_mfa_verify_profile_mfa_verify_post":{"properties":{"totp_code":{"type":"string","title":"Totp Code"}},"type":"object","required":["totp_code"],"title":"Body_mfa_verify_profile_mfa_verify_post"},"Body_remove_alert_email_org_notifications_email_remove_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_remove_alert_email_org_notifications_email_remove_post"},"Body_reset_password_confirm_reset_password_confirm_post":{"properties":{"token":{"type":"string","title":"Token"},"password":{"type":"string","title":"Password"},"confirm":{"type":"string","title":"Confirm"}},"type":"object","required":["token","password","confirm"],"title":"Body_reset_password_confirm_reset_password_confirm_post"},"Body_reset_password_request_reset_password_post":{"properties":{"email":{"type":"string","title":"Email"}},"type":"object","required":["email"],"title":"Body_reset_password_request_reset_password_post"},"Body_resolve_finding_findings__finding_id__resolve_post":{"properties":{"note":{"type":"string","title":"Note","default":""}},"type":"object","title":"Body_resolve_finding_findings__finding_id__resolve_post"},"Body_restrict_finding_findings__finding_id__restrict_post":{"properties":{"note":{"type":"string","title":"Note","default":""}},"type":"object","title":"Body_restrict_finding_findings__finding_id__restrict_post"},"Body_save_private_token_github_token_save_post":{"properties":{"token":{"type":"string","title":"Token"}},"type":"object","required":["token"],"title":"Body_save_private_token_github_token_save_post"},"Body_set_analyst_note_findings__finding_id__note_post":{"properties":{"note":{"type":"string","title":"Note","default":""}},"type":"object","title":"Body_set_analyst_note_findings__finding_id__note_post"},"Body_set_credential_name_findings__finding_id__name_post":{"properties":{"name":{"type":"string","title":"Name","default":""}},"type":"object","title":"Body_set_credential_name_findings__finding_id__name_post"},"Body_set_jira_integrations_notifications_jira_post":{"properties":{"jira_url":{"type":"string","title":"Jira Url","default":""},"jira_email":{"type":"string","title":"Jira Email","default":""},"jira_token":{"type":"string","title":"Jira Token","default":""},"project_key":{"type":"string","title":"Project Key","default":""}},"type":"object","title":"Body_set_jira_integrations_notifications_jira_post"},"Body_set_linear_integrations_notifications_linear_post":{"properties":{"linear_api_key":{"type":"string","title":"Linear Api Key","default":""},"linear_team_id":{"type":"string","title":"Linear Team Id","default":""}},"type":"object","title":"Body_set_linear_integrations_notifications_linear_post"},"Body_set_mfa_enforcement_org_security_mfa_enforcement_post":{"properties":{"mfa_required":{"type":"string","title":"Mfa Required","default":""}},"type":"object","title":"Body_set_mfa_enforcement_org_security_mfa_enforcement_post"},"Body_set_opsgenie_integrations_notifications_opsgenie_post":{"properties":{"api_key":{"type":"string","title":"Api Key","default":""}},"type":"object","title":"Body_set_opsgenie_integrations_notifications_opsgenie_post"},"Body_set_outbound_webhook_integrations_notifications_webhook_post":{"properties":{"webhook_url":{"type":"string","title":"Webhook Url","default":""}},"type":"object","title":"Body_set_outbound_webhook_integrations_notifications_webhook_post"},"Body_set_pagerduty_integrations_notifications_pagerduty_post":{"properties":{"routing_key":{"type":"string","title":"Routing Key","default":""}},"type":"object","title":"Body_set_pagerduty_integrations_notifications_pagerduty_post"},"Body_set_scan_interval_org_general_scan_interval_post":{"properties":{"scan_interval_hours":{"type":"string","title":"Scan Interval Hours","default":""}},"type":"object","title":"Body_set_scan_interval_org_general_scan_interval_post"},"Body_set_slack_webhook_integrations_notifications_slack_post":{"properties":{"webhook_url":{"type":"string","title":"Webhook Url","default":""}},"type":"object","title":"Body_set_slack_webhook_integrations_notifications_slack_post"},"Body_set_tags_findings__finding_id__tags_post":{"properties":{"tags":{"type":"string","title":"Tags","default":""}},"type":"object","title":"Body_set_tags_findings__finding_id__tags_post"},"Body_signup_submit_signup_post":{"properties":{"email":{"type":"string","title":"Email"},"company":{"type":"string","title":"Company"},"password":{"type":"string","title":"Password"},"confirm":{"type":"string","title":"Confirm"}},"type":"object","required":["email","company","password","confirm"],"title":"Body_signup_submit_signup_post"},"Body_team_change_role_org_team__user_id__role_post":{"properties":{"role":{"type":"string","title":"Role"}},"type":"object","required":["role"],"title":"Body_team_change_role_org_team__user_id__role_post"},"Body_team_change_role_team__user_id__role_post":{"properties":{"role":{"type":"string","title":"Role"}},"type":"object","required":["role"],"title":"Body_team_change_role_team__user_id__role_post"},"Body_team_invite_org_team_invite_post":{"properties":{"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role","default":"analyst"}},"type":"object","required":["email"],"title":"Body_team_invite_org_team_invite_post"},"Body_team_invite_team_invite_post":{"properties":{"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role","default":"analyst"}},"type":"object","required":["email"],"title":"Body_team_invite_team_invite_post"},"Body_update_email_profile_email_post":{"properties":{"email":{"type":"string","title":"Email","default":""}},"type":"object","title":"Body_update_email_profile_email_post"},"Body_upload_domains_domains_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_domains_domains_upload_post"},"Body_verify_domain_domains__dv_id__verify_post":{"properties":{"method":{"type":"string","title":"Method"}},"type":"object","required":["method"],"title":"Body_verify_domain_domains__dv_id__verify_post"},"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"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}