{"openapi":"3.1.0","info":{"title":"SecQon API","description":"Evidence-validated external VAPT platform — Infiqon Pvt Ltd.","version":"0.1.0"},"paths":{"/health":{"get":{"tags":["meta"],"summary":"Health","description":"Liveness. Proves the process is answering HTTP and nothing else.\n\nDeliberately dependency-free: a liveness probe that fails when the\ndatabase is unreachable would restart a container that is working\nperfectly, and restarting it does not bring Cloud SQL back.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Health Get"}}}}}}},"/health/ready":{"get":{"tags":["meta"],"summary":"Ready","description":"Readiness: can this process reach the database it needs?\n\nThe check `/health` never made. A drained connection pool, a Cloud SQL\ninstance that has gone away and a withdrawn private-IP route all leave\nthe process answering `/health` with a cheerful \"ok\" while every\nrequest that touches data returns 500. This is what the uptime check in\ninfra/gcp/alerts.tf watches.\n\nThe body says only whether it worked. This endpoint is public — Cloud\nRun serves it to allUsers — so the reason stays in the logs, where it\nis written with a stack trace for Error Reporting.","operationId":"ready_health_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Ready Health Ready Get"}}}}}}},"/auth/signup":{"post":{"tags":["auth"],"summary":"Signup","operationId":"signup_auth_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/login":{"post":{"tags":["auth"],"summary":"Login","operationId":"login_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/password/forgot":{"post":{"tags":["auth"],"summary":"Forgot Password","description":"Email a reset link. Always 202, so absence of an account is not leaked.","operationId":"forgot_password_auth_password_forgot_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordForgotRequest"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Forgot Password Auth Password Forgot Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/password/reset":{"post":{"tags":["auth"],"summary":"Reset Password","description":"Consume a reset token and set a new password.","operationId":"reset_password_auth_password_reset_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PasswordResetRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/legal":{"get":{"tags":["legal"],"summary":"List Documents","description":"The three documents and their current versions. Public.","operationId":"list_documents_legal_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/LegalDocSummary"},"type":"array","title":"Response List Documents Legal Get"}}}}}}},"/legal/status":{"get":{"tags":["legal"],"summary":"Acceptance Status","description":"What this user has accepted, and what they still owe.","operationId":"acceptance_status_legal_status_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegalStatusOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/legal/accept":{"post":{"tags":["legal"],"summary":"Accept","description":"Accept the current version of one or more documents.\n\nUsed when a document is amended after signup. Every document must end up\ncurrent — a partial acceptance is refused rather than half-recorded, so the\nuser is never left in a state where some of the agreement is stale.","operationId":"accept_legal_accept_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegalAcceptRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegalStatusOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/legal/{doc_id}":{"get":{"tags":["legal"],"summary":"Get Document Text","description":"Full Markdown of one document. Public — anyone may read the terms.","operationId":"get_document_text_legal__doc_id__get","parameters":[{"name":"doc_id","in":"path","required":true,"schema":{"type":"string","title":"Doc Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LegalDocOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets":{"post":{"tags":["assets"],"summary":"Add Asset","operationId":"add_asset_assets_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["assets"],"summary":"List Assets","operationId":"list_assets_assets_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AssetOut"},"title":"Response List Assets Assets Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}":{"get":{"tags":["assets"],"summary":"Get Asset","operationId":"get_asset_assets__asset_id__get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["assets"],"summary":"Delete Asset","description":"Remove an asset and everything derived from it.\n\nA mistyped domain was previously unrecoverable: on the one-asset Free tier\nit consumed the only slot forever. Removal cascades to the asset's\nverification records and scan targets, so the quota is genuinely freed.\n\nAudited, because removing an asset withdraws the authorisation to test it —\nthe same class of event as granting it.","operationId":"delete_asset_assets__asset_id__delete","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}/monitoring":{"patch":{"tags":["assets"],"summary":"Set Monitoring","description":"Turn scheduled re-testing on or off for one asset.\n\nPausing is not the same as deleting: the asset stays verified and keeps its\nhistory, it simply stops being picked up by the scheduler. Re-enabling\nmakes it due on the next tick.","operationId":"set_monitoring_assets__asset_id__monitoring_patch","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetMonitoringUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssetOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}/discovery":{"post":{"tags":["assets"],"summary":"Run Discovery","description":"Find the subdomains of a verified apex and propose them as candidates.\n\nNothing is sent to anything discovered — the sources are certificate\ntransparency logs and passive DNS, which are public records about names\nrather than the names themselves. That is what makes it safe to run before\nownership is proven, and it is also why the result is a proposal: we have\nobserved that a name exists, which is not the same as the tenant owning it.","operationId":"run_discovery_assets__asset_id__discovery_post","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoveryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["assets"],"summary":"List Discovery","description":"The candidates a previous run proposed for this apex. Runs nothing.\n\nReading the list is not a change to what the account may test, so unlike the\nrun itself it is not behind `require_write` — a read_only seat can see the\nattack surface without being able to add to it.","operationId":"list_discovery_assets__asset_id__discovery_get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoveryOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}/credentials":{"put":{"tags":["assets"],"summary":"Set Asset Credentials","description":"Store (or replace) the session headers used for authenticated scanning.\n\nIdempotent per asset: the unique constraint means re-configuring overwrites\nthe single row rather than accumulating. The values are sealed here and are\nnever returned by any endpoint.","operationId":"set_asset_credentials_assets__asset_id__credentials_put","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialSet"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["assets"],"summary":"Get Asset Credentials Status","description":"Report whether authenticated-scan credentials are configured — never the\nvalues themselves (there is deliberately no endpoint that returns them).","operationId":"get_asset_credentials_status_assets__asset_id__credentials_get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["assets"],"summary":"Delete Asset Credentials","description":"Remove stored credentials for an asset. Idempotent: clearing when none\nare configured succeeds (the desired end state is 'none').","operationId":"delete_asset_credentials_assets__asset_id__credentials_delete","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}/verify":{"get":{"tags":["verification"],"summary":"Outstanding","description":"The token already issued for this asset, so the UI can restore it.\n\nWithout this the client forgets the token on every reload and the only way\nback is ``start``, which would hand out a *different* token and silently\ninvalidate the DNS record the user already published.\n\nA lapsed asset gets its instructions back too, and this is what makes\nre-verification one click: the record it should still be publishing is the\none it was verified with, so the panel restores that token and offers\n\"Re-check now\" rather than sending the customer back to their registrar.","operationId":"outstanding_assets__asset_id__verify_get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/VerificationInstructions"},{"type":"null"}],"title":"Response Outstanding Assets  Asset Id  Verify Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}/verify/start":{"post":{"tags":["verification"],"summary":"Start","operationId":"start_assets__asset_id__verify_start_post","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationStart"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationInstructions"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}/verify/check":{"post":{"tags":["verification"],"summary":"Check","operationId":"check_assets__asset_id__verify_check_post","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerificationResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans":{"post":{"tags":["scans"],"summary":"Launch Scan","operationId":"launch_scan_scans_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["scans"],"summary":"List Scans","description":"Every scan this tenant has run, newest first.\n\nCarries each scan's targets and finding count so the history is readable\nwithout a request per row.","operationId":"list_scans_scans_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScanOut"},"title":"Response List Scans Scans Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/{scan_id}":{"get":{"tags":["scans"],"summary":"Get Scan","operationId":"get_scan_scans__scan_id__get","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","title":"Scan Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/{scan_id}/cancel":{"post":{"tags":["scans"],"summary":"Cancel Scan","description":"Stop a scan that is queued or already running.\n\nThis product points live traffic at a customer's production systems, so\nstopping is a trust control rather than a convenience. It is deliberately\n**not** gated on ``require_legal_current`` the way launching is: withdrawing\nauthorisation must never be blocked by a document the account has yet to\nre-accept.\n\nAudited as the kill switch, because at scan scale that is exactly what it\nis — a human deciding that no further traffic is authorised.","operationId":"cancel_scan_scans__scan_id__cancel_post","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scan Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scans/{scan_id}/findings":{"get":{"tags":["findings"],"summary":"List Scan Findings","operationId":"list_scan_findings_scans__scan_id__findings_get","parameters":[{"name":"scan_id","in":"path","required":true,"schema":{"type":"string","title":"Scan Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindingOut"},"title":"Response List Scan Findings Scans  Scan Id  Findings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings":{"get":{"tags":["findings"],"summary":"List Findings","operationId":"list_findings_findings_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FindingOut"},"title":"Response List Findings Findings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/remediation":{"get":{"tags":["findings"],"summary":"Remediation Record","description":"Closure evidence for every issue on the account that stopped reproducing.\n\nLive, and deliberately so — this backs the in-app view, where the question\nis \"what has been closed as of now\". The report takes the same ledger cut at\nits own scan's date, so a shared document stays a dated artifact (§11.3)\nwhile this screen stays current.","operationId":"remediation_record_findings_remediation_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RemediationOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findings/{finding_id}/status":{"patch":{"tags":["findings"],"summary":"Update Status","operationId":"update_status_findings__finding_id__status_patch","parameters":[{"name":"finding_id","in":"path","required":true,"schema":{"type":"string","title":"Finding Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindingStatusUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FindingOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports":{"post":{"tags":["reports"],"summary":"Create Report","operationId":"create_report_reports_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["reports"],"summary":"List Reports","operationId":"list_reports_reports_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReportOut"},"title":"Response List Reports Reports Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{report_id}/share":{"post":{"tags":["reports"],"summary":"Share Report","description":"Mint (or return) the public read-only link for a report.\n\nSharing is a deliberate act: ``/r/{token}`` needs no auth, so a report is\nonly given a token when the owner asks for one, never as a side effect of\ngenerating it. Idempotent — re-sharing returns the same link rather than\ninvalidating one already sent to an auditor.\n\nMinting also freezes the document (see ``Report.shared_html``): the link\nserves what the report said today, not what it will say in April.","operationId":"share_report_reports__report_id__share_post","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["reports"],"summary":"Unshare Report","description":"Revoke the public link. The report itself is untouched.\n\nSharing hands out a credential in a URL, so it has to be withdrawable —\notherwise a link forwarded to the wrong person can never be taken back.\n\nThe frozen snapshot goes with the token: nothing is left for a future share\nto accidentally resurrect, so re-sharing mints a fresh document rather than\nrepublishing a stale one under a new link.","operationId":"unshare_report_reports__report_id__share_delete","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{report_id}.html":{"get":{"tags":["reports"],"summary":"Report Html","operationId":"report_html_reports__report_id__html_get","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{report_id}.pdf":{"get":{"tags":["reports"],"summary":"Report Pdf","operationId":"report_pdf_reports__report_id__pdf_get","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/r/{share_token}":{"get":{"tags":["reports"],"summary":"Shared Report","description":"Public read-only report via share token (no auth). Only works if the\nowner explicitly made the report shareable.\n\nServes the snapshot frozen when the token was minted, never a fresh query:\nthe recipient is holding a dated document, and the same URL must keep\nreturning the same document. The as-of date is printed on its cover.","operationId":"shared_report_r__share_token__get","parameters":[{"name":"share_token","in":"path","required":true,"schema":{"type":"string","title":"Share Token"}}],"responses":{"200":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{report_id}/questionnaire.html":{"get":{"tags":["reports"],"summary":"Questionnaire Html","operationId":"questionnaire_html_reports__report_id__questionnaire_html_get","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reports/{report_id}/questionnaire.pdf":{"get":{"tags":["reports"],"summary":"Questionnaire Pdf","operationId":"questionnaire_pdf_reports__report_id__questionnaire_pdf_get","parameters":[{"name":"report_id","in":"path","required":true,"schema":{"type":"string","title":"Report Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instant-check":{"post":{"tags":["instant-check"],"summary":"Instant Check","operationId":"instant_check_instant_check_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstantCheckRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstantCheckResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/instant-check/{check_id}/email":{"post":{"tags":["instant-check"],"summary":"Capture Email","description":"Attach an email address to a check the visitor just ran.\n\nDeliberately thin: it records interest against a result that already\nexists. It does not create an account, does not send anything on its own,\nand cannot be used to look a result up — the id is returned only to the\ncaller who ran the check, and this route never reads a row back out. That\nkeeps a public, unauthenticated endpoint from becoming a way to enumerate\nwho scanned what.\n\nRate-limited on the same bucket as the check itself, so it cannot be used\nas an unmetered write endpoint.","operationId":"capture_email_instant_check__check_id__email_post","parameters":[{"name":"check_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Check Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstantCheckEmailRequest"}}}},"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/plans":{"get":{"tags":["billing"],"summary":"List Plans","description":"Our tiers (what you get) joined to Billing's prices (what you pay).\n\nQuotas are ours; money is Billing's. Hardcoding a price here would let the\npricing page drift from the invoice (INTEGRATION §0), so if Billing is\nunreachable the tier is returned with no prices and the UI says \"contact\nus\" rather than showing a number we invented.","operationId":"list_plans_plans_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PlanOut"},"type":"array","title":"Response List Plans Plans Get"}}}}}}},"/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout","description":"Start a purchase for a catalog plan.\n\nWe name the plan and let Billing supply the price (INTEGRATION §1) — the\nbutton cannot restate a number it does not own, and an `amountMinor` that\ncontradicts the plan is a 400 by design, so we send none.\n\nGST: an Indian customer needs a state code or a GSTIN. Refused here with a\nreadable message rather than passed through to a 400 from Billing.","operationId":"create_checkout_billing_checkout_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/sessions/{session_id}":{"get":{"tags":["billing"],"summary":"Session Status","operationId":"session_status_billing_sessions__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Session Status Billing Sessions  Session Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/subscription":{"get":{"tags":["billing"],"summary":"Current Subscription","operationId":"current_subscription_billing_subscription_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Current Subscription Billing Subscription Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["billing"],"summary":"Cancel Own Subscription","description":"Cancel the caller's own subscription — the one the dashboard calls.\n\nAddressed by the session rather than by an id, because the customer's\nbrowser has no business knowing Billing's identifiers and the account holds\nexactly one subscription. The id-addressed route below stays for anything\nthat already has an id in hand.","operationId":"cancel_own_subscription_billing_subscription_delete","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cancel Own Subscription Billing Subscription Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/subscriptions/{sub_id}":{"get":{"tags":["billing"],"summary":"Get Subscription","operationId":"get_subscription_billing_subscriptions__sub_id__get","parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"string","title":"Sub Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Subscription Billing Subscriptions  Sub Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["billing"],"summary":"Cancel Subscription","operationId":"cancel_subscription_billing_subscriptions__sub_id__delete","parameters":[{"name":"sub_id","in":"path","required":true,"schema":{"type":"string","title":"Sub Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cancel Subscription Billing Subscriptions  Sub Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/subscription/change-plan":{"post":{"tags":["billing"],"summary":"Change Subscription Plan","description":"Move the caller's own subscription to another tier, prorated.\n\nThis is the answer to the thing a tester hit within minutes of the paid flow\ngoing live: buying a second plan started a fresh checkout at the full price\nand simply forfeited the days left on the first. Here the gateway works out\nthe difference and charges or refunds it, and no tax document is computed on\nthis side — a credit note is statutory, and the gateway that took the money\nraises it.\n\nOnly a real recurring subscription can be moved. A tenant whose purchase was\na one-off order has nothing to change, and is told to buy instead of being\nhanded a gateway error about a subscription id that does not exist.","operationId":"change_subscription_plan_billing_subscription_change_plan_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePlanRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Change Subscription Plan Billing Subscription Change Plan Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/invoices/{id_or_number}":{"get":{"tags":["billing"],"summary":"Get Invoice","operationId":"get_invoice_billing_invoices__id_or_number__get","parameters":[{"name":"id_or_number","in":"path","required":true,"schema":{"type":"string","title":"Id Or Number"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Invoice Billing Invoices  Id Or Number  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/invoices/{invoice_id}/pdf":{"get":{"tags":["billing"],"summary":"Get Invoice Pdf","operationId":"get_invoice_pdf_billing_invoices__invoice_id__pdf_get","parameters":[{"name":"invoice_id","in":"path","required":true,"schema":{"type":"string","title":"Invoice Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alert-rules":{"post":{"tags":["monitoring"],"summary":"Create Rule","operationId":"create_rule_alert_rules_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AlertRuleOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["monitoring"],"summary":"List Rules","operationId":"list_rules_alert_rules_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AlertRuleOut"},"title":"Response List Rules Alert Rules Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/alert-rules/{rule_id}":{"delete":{"tags":["monitoring"],"summary":"Delete Rule","operationId":"delete_rule_alert_rules__rule_id__delete","parameters":[{"name":"rule_id","in":"path","required":true,"schema":{"type":"string","title":"Rule Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assets/{asset_id}/diff":{"get":{"tags":["monitoring"],"summary":"Asset Diff","description":"Diff the two most recent COMPLETED scans covering this asset.","operationId":"asset_diff_assets__asset_id__diff_get","parameters":[{"name":"asset_id","in":"path","required":true,"schema":{"type":"string","title":"Asset Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanDiffOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/members":{"get":{"tags":["team"],"summary":"List Members","description":"Everyone with a seat here. Readable by every role, including read_only:\nknowing who else can see your findings is not a privilege.","operationId":"list_members_team_members_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MemberOut"},"title":"Response List Members Team Members Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/members/{member_id}":{"patch":{"tags":["team"],"summary":"Update Member","description":"Change a seat's role, or deactivate it.\n\nDeactivation rather than deletion: the audit chain and every finding this\nperson touched reference their user id, and a dangling actor turns a\ncomplete record into a puzzle. An inactive user cannot log in and their\nexisting token stops working on the next request (``get_current_user``\nre-reads ``is_active`` from the database on every call).","operationId":"update_member_team_members__member_id__patch","parameters":[{"name":"member_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Member Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/invites":{"get":{"tags":["team"],"summary":"List Invites","operationId":"list_invites_team_invites_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/InviteOut"},"title":"Response List Invites Team Invites Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["team"],"summary":"Create Invite","operationId":"create_invite_team_invites_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/invites/{invite_id}":{"delete":{"tags":["team"],"summary":"Revoke Invite","operationId":"revoke_invite_team_invites__invite_id__delete","parameters":[{"name":"invite_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invite Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/invites/accept/{token}":{"get":{"tags":["team"],"summary":"Preview Invite","description":"What the accept page may show before anyone signs in.","operationId":"preview_invite_team_invites_accept__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitePreview"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/team/invites/accept":{"post":{"tags":["team"],"summary":"Accept Invite","description":"Redeem an invitation into a real seat.\n\nThe role comes from the stored invite, never from this request. The three\nlegal acceptances are as non-skippable as they are at signup: a new person\nwith the power to authorise testing has to agree to the RoE in their own\nname, not inherit their inviter's acceptance.","operationId":"accept_invite_team_invites_accept_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteAccept"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api-keys":{"get":{"tags":["api-keys"],"summary":"List Api Keys","operationId":"list_api_keys_api_keys_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyOut"},"title":"Response List Api Keys Api Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["api-keys"],"summary":"Create Api Key","description":"Mint a key. The plaintext is in this response and nowhere else.\n\n``require_write`` does the first two refusals for free, and both are\nwanted: a ``read_only`` seat cannot mint a standing credential at all (it\nhas nothing to delegate, and a headless key from a read-only seat is still\na headless key), and a ``platform_admin`` cannot mint one against a\ncustomer tenant — staff act through the audited console in ``admin.py`` or\nnot at all.","operationId":"create_api_key_api_keys_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreate"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api-keys/{key_id}":{"delete":{"tags":["api-keys"],"summary":"Revoke Api Key","description":"Revoke immediately. The next request the key makes is refused.\n\nRevocation is a stamp, not a delete: the row is the record of what existed,\nand the audit entry that mentions its prefix would otherwise point at\nnothing. Revoking an already-revoked key is a no-op rather than an error —\nthe caller's intent is already true, and someone racing to kill a leaked\ncredential should not have to read an error message to find that out.","operationId":"revoke_api_key_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AdminAuditRow":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"at":{"type":"string","format":"date-time","title":"At"},"tenant_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Tenant Id"},"tenant_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tenant Name"},"actor":{"type":"string","title":"Actor"},"action":{"type":"string","title":"Action"},"target":{"type":"string","title":"Target"},"detail":{"additionalProperties":true,"type":"object","title":"Detail"},"ip":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ip"},"hash":{"type":"string","title":"Hash"},"prev_hash":{"type":"string","title":"Prev Hash"}},"type":"object","required":["id","at","tenant_id","tenant_name","actor","action","target","detail","ip","hash","prev_hash"],"title":"AdminAuditRow"},"AdminAuditVerdict":{"properties":{"scope":{"type":"string","title":"Scope"},"ok":{"type":"boolean","title":"Ok"},"events":{"type":"integer","title":"Events"},"head_count":{"type":"integer","title":"Head Count"},"tail_hash":{"type":"string","title":"Tail Hash"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason"}},"type":"object","required":["scope","ok","events","head_count","tail_hash"],"title":"AdminAuditVerdict","description":"The result of re-walking a scope's hash chain.\n\n``ok`` false means the persisted chain does not recompute — either an event\nwas edited or the tail was truncated. That is a security incident, not a\ndisplay bug, so the reason is surfaced verbatim."},"AdminCounts":{"properties":{"total":{"type":"integer","title":"Total"},"new_7d":{"type":"integer","title":"New 7D","default":0}},"type":"object","required":["total"],"title":"AdminCounts"},"AdminDisableRequest":{"properties":{"reason":{"type":"string","maxLength":500,"minLength":3,"title":"Reason"}},"type":"object","required":["reason"],"title":"AdminDisableRequest","description":"The kill switch. A reason is mandatory — an unexplained disabled account\nis indistinguishable from an outage, and the reason is what the audit entry\nis actually for."},"AdminOverview":{"properties":{"generated_at":{"type":"string","format":"date-time","title":"Generated At"},"tenants":{"$ref":"#/components/schemas/AdminCounts"},"active_tenants":{"type":"integer","title":"Active Tenants"},"disabled_tenants":{"type":"integer","title":"Disabled Tenants"},"users":{"$ref":"#/components/schemas/AdminCounts"},"assets":{"$ref":"#/components/schemas/AdminCounts"},"verified_assets":{"type":"integer","title":"Verified Assets"},"scans":{"$ref":"#/components/schemas/AdminCounts"},"scans_24h":{"type":"integer","title":"Scans 24H"},"scans_running":{"type":"integer","title":"Scans Running"},"scans_failed_24h":{"type":"integer","title":"Scans Failed 24H"},"findings_open":{"type":"integer","title":"Findings Open"},"findings_by_severity":{"additionalProperties":{"type":"integer"},"type":"object","title":"Findings By Severity"},"confirmed_findings":{"type":"integer","title":"Confirmed Findings"},"plan_mix":{"additionalProperties":{"type":"integer"},"type":"object","title":"Plan Mix"},"mrr_usd_minor_estimate":{"type":"integer","title":"Mrr Usd Minor Estimate"}},"type":"object","required":["generated_at","tenants","active_tenants","disabled_tenants","users","assets","verified_assets","scans","scans_24h","scans_running","scans_failed_24h","findings_open","findings_by_severity","confirmed_findings","plan_mix","mrr_usd_minor_estimate"],"title":"AdminOverview","description":"The staff dashboard in one round trip."},"AdminPlanOverride":{"properties":{"plan_code":{"$ref":"#/components/schemas/PlanCode"},"reason":{"type":"string","maxLength":500,"minLength":3,"title":"Reason"},"asset_quota":{"anyOf":[{"type":"integer","maximum":10000.0,"minimum":0.0},{"type":"null"}],"title":"Asset Quota"}},"type":"object","required":["plan_code","reason"],"title":"AdminPlanOverride"},"AdminScanRow":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"tenant_name":{"type":"string","title":"Tenant Name"},"profile":{"type":"string","title":"Profile"},"status":{"type":"string","title":"Status"},"trigger":{"type":"string","title":"Trigger"},"progress":{"type":"integer","title":"Progress"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"finding_count":{"type":"integer","title":"Finding Count"},"targets":{"items":{"type":"string"},"type":"array","title":"Targets"}},"type":"object","required":["id","tenant_id","tenant_name","profile","status","trigger","progress","created_at","finished_at","error","finding_count","targets"],"title":"AdminScanRow"},"AdminServiceHealth":{"properties":{"services":{"items":{"$ref":"#/components/schemas/AdminServiceRow"},"type":"array","title":"Services"},"overall":{"type":"string","title":"Overall"},"down":{"type":"integer","title":"Down"},"degraded":{"type":"integer","title":"Degraded"},"not_configured":{"type":"integer","title":"Not Configured"}},"type":"object","required":["services","overall","down","degraded","not_configured"],"title":"AdminServiceHealth"},"AdminServiceRow":{"properties":{"key":{"type":"string","title":"Key"},"name":{"type":"string","title":"Name"},"health":{"type":"string","title":"Health"},"impact":{"type":"string","title":"Impact"},"detail":{"type":"string","title":"Detail"},"optional":{"type":"boolean","title":"Optional"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"}},"type":"object","required":["key","name","health","impact","detail","optional","tags"],"title":"AdminServiceRow","description":"One platform dependency, and what its being down actually costs.\n\n`impact` is the field that matters: a red row on the console must tell an\noperator that (say) A10 is no longer being assessed, not merely that\nsomething is unreachable."},"AdminTenantDetail":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"disabled":{"type":"boolean","title":"Disabled"},"disabled_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disabled Reason"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"plan_code":{"anyOf":[{"$ref":"#/components/schemas/PlanCode"},{"type":"null"}]},"subscription_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Status"},"user_count":{"type":"integer","title":"User Count"},"asset_count":{"type":"integer","title":"Asset Count"},"verified_asset_count":{"type":"integer","title":"Verified Asset Count"},"scan_count":{"type":"integer","title":"Scan Count"},"open_findings":{"type":"integer","title":"Open Findings"},"last_scan_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Scan At"},"users":{"items":{"$ref":"#/components/schemas/MemberOut"},"type":"array","title":"Users"},"recent_scans":{"items":{"$ref":"#/components/schemas/ScanOut"},"type":"array","title":"Recent Scans"},"findings_by_severity":{"additionalProperties":{"type":"integer"},"type":"object","title":"Findings By Severity"},"asset_quota":{"type":"integer","title":"Asset Quota"},"assets":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Assets"}},"type":"object","required":["id","name","disabled","disabled_reason","created_at","plan_code","subscription_status","user_count","asset_count","verified_asset_count","scan_count","open_findings","last_scan_at","users","recent_scans","findings_by_severity","asset_quota","assets"],"title":"AdminTenantDetail"},"AdminTenantPage":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/AdminTenantRow"},"type":"array","title":"Rows"},"total":{"type":"integer","title":"Total"},"page":{"type":"integer","title":"Page"},"page_size":{"type":"integer","title":"Page Size"}},"type":"object","required":["rows","total","page","page_size"],"title":"AdminTenantPage"},"AdminTenantRow":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"disabled":{"type":"boolean","title":"Disabled"},"disabled_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disabled Reason"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"plan_code":{"anyOf":[{"$ref":"#/components/schemas/PlanCode"},{"type":"null"}]},"subscription_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Status"},"user_count":{"type":"integer","title":"User Count"},"asset_count":{"type":"integer","title":"Asset Count"},"verified_asset_count":{"type":"integer","title":"Verified Asset Count"},"scan_count":{"type":"integer","title":"Scan Count"},"open_findings":{"type":"integer","title":"Open Findings"},"last_scan_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Scan At"}},"type":"object","required":["id","name","disabled","disabled_reason","created_at","plan_code","subscription_status","user_count","asset_count","verified_asset_count","scan_count","open_findings","last_scan_at"],"title":"AdminTenantRow"},"AdminTimePoint":{"properties":{"day":{"type":"string","format":"date","title":"Day"},"signups":{"type":"integer","title":"Signups"},"scans":{"type":"integer","title":"Scans"},"findings":{"type":"integer","title":"Findings"}},"type":"object","required":["day","signups","scans","findings"],"title":"AdminTimePoint"},"AdminUserRow":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"role":{"$ref":"#/components/schemas/UserRole"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_login_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Login At"},"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"tenant_name":{"type":"string","title":"Tenant Name"},"tenant_disabled":{"type":"boolean","title":"Tenant Disabled"}},"type":"object","required":["id","email","role","is_active","created_at","last_login_at","tenant_id","tenant_name","tenant_disabled"],"title":"AdminUserRow"},"AdminUserUpdate":{"properties":{"is_active":{"type":"boolean","title":"Is Active"},"reason":{"type":"string","maxLength":500,"minLength":3,"title":"Reason"}},"type":"object","required":["is_active","reason"],"title":"AdminUserUpdate"},"AlertRuleCreate":{"properties":{"channel":{"type":"string","title":"Channel"},"target":{"type":"string","maxLength":500,"minLength":1,"title":"Target"},"min_severity":{"type":"string","title":"Min Severity","default":"high"}},"type":"object","required":["channel","target"],"title":"AlertRuleCreate"},"AlertRuleOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"channel":{"type":"string","title":"Channel"},"target":{"type":"string","title":"Target"},"min_severity":{"type":"string","title":"Min Severity"},"enabled":{"type":"boolean","title":"Enabled"}},"type":"object","required":["id","channel","target","min_severity","enabled"],"title":"AlertRuleOut"},"ApiKeyCreate":{"properties":{"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"scopes":{"items":{"$ref":"#/components/schemas/ApiScope"},"type":"array","minItems":1,"title":"Scopes"},"role":{"$ref":"#/components/schemas/UserRole","default":"read_only"},"expires_in_days":{"type":"integer","maximum":365.0,"minimum":1.0,"title":"Expires In Days","default":90}},"type":"object","required":["name","scopes"],"title":"ApiKeyCreate"},"ApiKeyCreated":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"prefix":{"type":"string","title":"Prefix"},"role":{"$ref":"#/components/schemas/UserRole"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"can_revoke":{"type":"boolean","title":"Can Revoke","default":false},"key":{"type":"string","title":"Key"}},"type":"object","required":["id","name","prefix","role","scopes","status","created_at","key"],"title":"ApiKeyCreated"},"ApiKeyOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"prefix":{"type":"string","title":"Prefix"},"role":{"$ref":"#/components/schemas/UserRole"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"created_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By Email"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"can_revoke":{"type":"boolean","title":"Can Revoke","default":false}},"type":"object","required":["id","name","prefix","role","scopes","status","created_at"],"title":"ApiKeyOut","description":"A key as the management screen sees it. No secret material, ever."},"ApiScope":{"type":"string","enum":["assets:read","assets:write","scans:read","scans:run","findings:read","findings:write","reports:read","reports:write"],"title":"ApiScope","description":"What a key may do, granted one capability at a time.\n\nDeliberately coarser than the route table and deliberately narrower than a\nsession. There is no scope for team administration, billing, plan changes,\nlegal acceptance, per-asset scan credentials, or for minting another API\nkey — those are things a person does once, with an account behind them, not\nthings a build server should be able to do at 3am with a leaked variable.\nTheir absence is the enforcement: ``deps.py`` refuses any path no scope\nnames, so an endpoint added later is unreachable by a key until somebody\ndecides otherwise."},"AssetCreate":{"properties":{"type":{"$ref":"#/components/schemas/AssetType"},"value":{"type":"string","maxLength":255,"minLength":1,"title":"Value"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group"},"attest_authorized":{"type":"boolean","title":"Attest Authorized","default":false}},"type":"object","required":["type","value"],"title":"AssetCreate"},"AssetMonitoringUpdate":{"properties":{"monitoring_enabled":{"type":"boolean","title":"Monitoring Enabled"}},"type":"object","required":["monitoring_enabled"],"title":"AssetMonitoringUpdate"},"AssetOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"type":{"$ref":"#/components/schemas/AssetType"},"value":{"type":"string","title":"Value"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"group":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group"},"verification_status":{"$ref":"#/components/schemas/VerificationStatus"},"is_scannable":{"type":"boolean","title":"Is Scannable"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"verified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Verified At"},"monitoring_enabled":{"type":"boolean","title":"Monitoring Enabled","default":true},"next_monitor_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Next Monitor At"},"last_monitored_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Monitored At"},"discovered_by":{"$ref":"#/components/schemas/DiscoveredBy","default":"manual"}},"type":"object","required":["id","type","value","label","group","verification_status","is_scannable","created_at"],"title":"AssetOut"},"AssetType":{"type":"string","enum":["domain","subdomain","ip","cidr","api_base_url"],"title":"AssetType"},"BillingPriceOut":{"properties":{"plan_id":{"type":"string","title":"Plan Id"},"billing_code":{"type":"string","title":"Billing Code"},"interval":{"type":"string","title":"Interval"},"amount_minor":{"type":"integer","title":"Amount Minor"},"currency":{"type":"string","title":"Currency"},"subscription_capable":{"type":"boolean","title":"Subscription Capable"}},"type":"object","required":["plan_id","billing_code","interval","amount_minor","currency","subscription_capable"],"title":"BillingPriceOut","description":"One purchasable price for a tier, as Billing defines it.\n\n`plan_id` is what checkout names — we never restate the amount, so our\nbutton cannot disagree with the invoice (INTEGRATION §0/§1)."},"ChangePlanRequest":{"properties":{"plan_id":{"type":"string","minLength":1,"title":"Plan Id"}},"type":"object","required":["plan_id"],"title":"ChangePlanRequest","description":"Move an existing subscription to another tier.\n\nOnly the target price is accepted. The schedule is deliberately not the\ncaller's to choose: an immediate, prorated change is the one a customer is\nasking for when they pick a different plan, and offering \"at period end\"\nhere would need a boundary sync that does not exist yet (INTEGRATION §3b)."},"CheckoutRequest":{"properties":{"plan_id":{"type":"string","minLength":1,"title":"Plan Id"},"country":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"},"state_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State Code"},"gstin":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Gstin"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"address":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Address"}},"type":"object","required":["plan_id"],"title":"CheckoutRequest","description":"Buy a catalog plan.\n\nOnly the plan and the customer's tax details come from the client: the name\nand email are taken from the signed-in account, and the price comes from\nBilling. Passing an amount that contradicts the plan is a 400 by design\n(INTEGRATION §1), so we never send one.\n\nThere is deliberately no ``mode``. It used to be here, defaulting to\n``\"order\"``, and no client ever sent anything else — so every purchase of a\nrecurring plan was billed as a single charge that never renewed. Whether a\nplan recurs is a fact about the plan, which Billing's catalog reports as\n``subscriptionCapable``, so the router reads it there."},"CheckoutSessionOut":{"properties":{"session_id":{"type":"string","title":"Session Id"},"url":{"type":"string","title":"Url"},"status":{"type":"string","title":"Status"},"mode":{"type":"string","title":"Mode"},"amount_minor":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Amount Minor"},"currency":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Currency"},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["session_id","url","status","mode"],"title":"CheckoutSessionOut"},"CredentialSet":{"properties":{"headers":{"additionalProperties":{"type":"string"},"type":"object","minProperties":1,"title":"Headers"}},"type":"object","required":["headers"],"title":"CredentialSet","description":"Session headers for authenticated scanning of one asset, e.g.\n{\"Cookie\": \"session=…\"} or {\"Authorization\": \"Bearer …\"}. Stored encrypted\nand never returned."},"CredentialStatus":{"properties":{"configured":{"type":"boolean","title":"Configured"}},"type":"object","required":["configured"],"title":"CredentialStatus"},"DiscoveredAssetOut":{"properties":{"asset":{"$ref":"#/components/schemas/AssetOut"},"sources":{"items":{"type":"string"},"type":"array","title":"Sources"},"resolves":{"type":"boolean","title":"Resolves","default":false},"addresses":{"items":{"type":"string"},"type":"array","title":"Addresses"},"routable":{"type":"boolean","title":"Routable","default":false},"cert_seen":{"type":"boolean","title":"Cert Seen","default":false},"rank":{"type":"integer","title":"Rank","default":0},"rank_reason":{"type":"string","title":"Rank Reason","default":""},"discovered_at":{"type":"string","format":"date-time","title":"Discovered At"}},"type":"object","required":["asset","discovered_at"],"title":"DiscoveredAssetOut","description":"One proposed subdomain and the passive evidence behind it.\n\nThe full ``AssetOut`` is embedded rather than summarised so the existing\nverification panel can be handed a candidate unchanged — the one-click\nverification is *the same flow*, not a parallel one."},"DiscoveredBy":{"type":"string","enum":["manual","recon"],"title":"DiscoveredBy"},"DiscoveryOut":{"properties":{"apex_asset_id":{"type":"string","format":"uuid","title":"Apex Asset Id"},"apex":{"type":"string","title":"Apex"},"ran":{"type":"boolean","title":"Ran"},"detail":{"type":"string","title":"Detail"},"candidates":{"items":{"$ref":"#/components/schemas/DiscoveredAssetOut"},"type":"array","title":"Candidates"},"created":{"type":"integer","title":"Created","default":0},"withheld":{"type":"integer","title":"Withheld","default":0}},"type":"object","required":["apex_asset_id","apex","ran","detail"],"title":"DiscoveryOut"},"FindingOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"scan_id":{"type":"string","format":"uuid","title":"Scan Id"},"asset_id":{"type":"string","format":"uuid","title":"Asset Id"},"category":{"type":"string","title":"Category"},"title":{"type":"string","title":"Title"},"severity":{"type":"string","title":"Severity"},"cvss":{"type":"number","title":"Cvss"},"exploitability":{"type":"string","title":"Exploitability"},"owasp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owasp"},"cwe":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwe"},"cve":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cve"},"source_tool":{"type":"string","title":"Source Tool"},"explanation":{"type":"string","title":"Explanation"},"remediation":{"type":"string","title":"Remediation"},"status":{"type":"string","title":"Status"},"evidence":{"additionalProperties":true,"type":"object","title":"Evidence"},"compliance":{"additionalProperties":true,"type":"object","title":"Compliance"},"dedup_key":{"type":"string","title":"Dedup Key"},"first_seen":{"type":"string","format":"date-time","title":"First Seen"},"last_seen":{"type":"string","format":"date-time","title":"Last Seen"}},"type":"object","required":["id","scan_id","asset_id","category","title","severity","cvss","exploitability","owasp","cwe","cve","source_tool","explanation","remediation","status","evidence","compliance","dedup_key","first_seen","last_seen"],"title":"FindingOut"},"FindingStatusUpdate":{"properties":{"status":{"type":"string","title":"Status"}},"type":"object","required":["status"],"title":"FindingStatusUpdate"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InstantCheckEmailRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"InstantCheckEmailRequest"},"InstantCheckRequest":{"properties":{"url":{"type":"string","maxLength":255,"minLength":3,"title":"Url"},"attribution":{"additionalProperties":{"type":"string"},"type":"object","title":"Attribution"}},"type":"object","required":["url"],"title":"InstantCheckRequest"},"InstantCheckResult":{"properties":{"check_id":{"type":"string","format":"uuid","title":"Check Id"},"host":{"type":"string","title":"Host"},"exposure_score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Exposure Score"},"grade":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grade"},"reachable":{"type":"boolean","title":"Reachable","default":true},"total_findings":{"type":"integer","title":"Total Findings"},"teaser":{"items":{"$ref":"#/components/schemas/TeaserFinding"},"type":"array","title":"Teaser"},"hidden_count":{"type":"integer","title":"Hidden Count"},"message":{"type":"string","title":"Message"}},"type":"object","required":["check_id","host","total_findings","teaser","hidden_count","message"],"title":"InstantCheckResult"},"InviteAccept":{"properties":{"token":{"type":"string","maxLength":128,"minLength":16,"title":"Token"},"password":{"type":"string","maxLength":200,"minLength":10,"title":"Password"},"accept_tos":{"type":"boolean","title":"Accept Tos"},"accept_aup":{"type":"boolean","title":"Accept Aup"},"accept_roe":{"type":"boolean","title":"Accept Roe"}},"type":"object","required":["token","password","accept_tos","accept_aup","accept_roe"],"title":"InviteAccept"},"InviteCreate":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"role":{"$ref":"#/components/schemas/UserRole","default":"member"}},"type":"object","required":["email"],"title":"InviteCreate"},"InviteOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"role":{"$ref":"#/components/schemas/UserRole"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"accepted_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Accepted At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"status":{"type":"string","title":"Status"},"accept_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accept Url"}},"type":"object","required":["id","email","role","created_at","expires_at","status"],"title":"InviteOut"},"InvitePreview":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"company_name":{"type":"string","title":"Company Name"},"role":{"$ref":"#/components/schemas/UserRole"},"invited_by_email":{"type":"string","format":"email","title":"Invited By Email"}},"type":"object","required":["email","company_name","role","invited_by_email"],"title":"InvitePreview","description":"What the public accept page may know before anyone authenticates.\n\nDeliberately thin: the company name and the role on offer, so the page can\nsay what is being joined. No member list, no asset counts, nothing that\nturns a leaked link into a reconnaissance tool."},"LegalAcceptRequest":{"properties":{"docs":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Docs"}},"type":"object","required":["docs"],"title":"LegalAcceptRequest"},"LegalDocOut":{"properties":{"doc":{"type":"string","title":"Doc"},"title":{"type":"string","title":"Title"},"version":{"type":"string","title":"Version"},"effective":{"type":"string","format":"date","title":"Effective"},"status":{"type":"string","title":"Status"},"summary":{"type":"string","title":"Summary"},"sha256":{"type":"string","title":"Sha256"},"body":{"type":"string","title":"Body"}},"type":"object","required":["doc","title","version","effective","status","summary","sha256","body"],"title":"LegalDocOut"},"LegalDocSummary":{"properties":{"doc":{"type":"string","title":"Doc"},"title":{"type":"string","title":"Title"},"version":{"type":"string","title":"Version"},"effective":{"type":"string","format":"date","title":"Effective"},"status":{"type":"string","title":"Status"},"summary":{"type":"string","title":"Summary"},"sha256":{"type":"string","title":"Sha256"}},"type":"object","required":["doc","title","version","effective","status","summary","sha256"],"title":"LegalDocSummary"},"LegalStatusOut":{"properties":{"accepted":{"additionalProperties":{"type":"string"},"type":"object","title":"Accepted"},"outstanding":{"items":{"$ref":"#/components/schemas/LegalDocSummary"},"type":"array","title":"Outstanding"},"all_current":{"type":"boolean","title":"All Current"}},"type":"object","required":["accepted","outstanding","all_current"],"title":"LegalStatusOut","description":"What this user has accepted vs. what is current."},"LoginRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","title":"Password"}},"type":"object","required":["email","password"],"title":"LoginRequest"},"MemberOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","format":"email","title":"Email"},"role":{"$ref":"#/components/schemas/UserRole"},"is_active":{"type":"boolean","title":"Is Active"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_login_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Login At"},"is_you":{"type":"boolean","title":"Is You","default":false}},"type":"object","required":["id","email","role","is_active","created_at"],"title":"MemberOut","description":"A seat in the caller's own account. No password material, ever."},"MemberUpdate":{"properties":{"role":{"anyOf":[{"$ref":"#/components/schemas/UserRole"},{"type":"null"}]},"is_active":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Active"}},"type":"object","title":"MemberUpdate"},"MonitorTickOut":{"properties":{"due":{"type":"integer","title":"Due"},"launched":{"type":"integer","title":"Launched"},"deferred":{"type":"integer","title":"Deferred"},"skipped_unverified":{"type":"integer","title":"Skipped Unverified"},"scan_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Scan Ids"}},"type":"object","required":["due","launched","deferred","skipped_unverified","scan_ids"],"title":"MonitorTickOut"},"PasswordForgotRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"PasswordForgotRequest"},"PasswordResetRequest":{"properties":{"token":{"type":"string","maxLength":128,"minLength":16,"title":"Token"},"password":{"type":"string","maxLength":200,"minLength":10,"title":"Password"}},"type":"object","required":["token","password"],"title":"PasswordResetRequest"},"PlanCode":{"type":"string","enum":["free","starter","growth","business","scale","one_off"],"title":"PlanCode"},"PlanOut":{"properties":{"code":{"$ref":"#/components/schemas/PlanCode"},"name":{"type":"string","title":"Name"},"asset_quota":{"type":"integer","title":"Asset Quota"},"monthly_usd_minor":{"type":"integer","title":"Monthly Usd Minor"},"annual_usd_minor":{"type":"integer","title":"Annual Usd Minor"},"prices":{"items":{"$ref":"#/components/schemas/BillingPriceOut"},"type":"array","title":"Prices"}},"type":"object","required":["code","name","asset_quota","monthly_usd_minor","annual_usd_minor"],"title":"PlanOut"},"RemediationOut":{"properties":{"proven":{"items":{"$ref":"#/components/schemas/RemediationRecordOut"},"type":"array","title":"Proven"},"claimed":{"items":{"$ref":"#/components/schemas/RemediationRecordOut"},"type":"array","title":"Claimed"},"unverified":{"items":{"$ref":"#/components/schemas/RemediationRecordOut"},"type":"array","title":"Unverified"}},"type":"object","required":["proven","claimed","unverified"],"title":"RemediationOut","description":"Three separate buckets, never one total.\n\nThey are returned pre-split rather than as a flat list with a state field so\na caller cannot accidentally sum them; the counts are the lengths of the\nlists, so a summary can never drift from what it summarises."},"RemediationRecordOut":{"properties":{"dedup_key":{"type":"string","title":"Dedup Key"},"asset_id":{"type":"string","format":"uuid","title":"Asset Id"},"title":{"type":"string","title":"Title"},"category":{"type":"string","title":"Category"},"severity":{"type":"string","title":"Severity"},"owasp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owasp"},"source_tool":{"type":"string","title":"Source Tool"},"stage":{"type":"string","title":"Stage"},"stage_label":{"type":"string","title":"Stage Label"},"state":{"type":"string","title":"State"},"marked_fixed":{"type":"boolean","title":"Marked Fixed"},"first_seen":{"type":"string","format":"date-time","title":"First Seen"},"last_observed":{"type":"string","format":"date-time","title":"Last Observed"},"observations":{"type":"integer","title":"Observations"},"closed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Closed At"},"retest":{"anyOf":[{"$ref":"#/components/schemas/RetestOut"},{"type":"null"}]},"statement":{"type":"string","title":"Statement"}},"type":"object","required":["dedup_key","asset_id","title","category","severity","owasp","source_tool","stage","stage_label","state","marked_fixed","first_seen","last_observed","observations","closed_at","retest","statement"],"title":"RemediationRecordOut"},"ReportCreate":{"properties":{"scan_id":{"type":"string","format":"uuid","title":"Scan Id"},"frameworks":{"items":{"type":"string"},"type":"array","title":"Frameworks"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"make_shareable":{"type":"boolean","title":"Make Shareable","default":false}},"type":"object","required":["scan_id"],"title":"ReportCreate"},"ReportOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"scan_ids":{"items":{},"type":"array","title":"Scan Ids"},"frameworks":{"items":{},"type":"array","title":"Frameworks"},"share_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Share Token"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","title","scan_ids","frameworks","share_token","created_at"],"title":"ReportOut"},"RetestOut":{"properties":{"scan_id":{"type":"string","format":"uuid","title":"Scan Id"},"at":{"type":"string","format":"date-time","title":"At"},"profile":{"type":"string","title":"Profile"},"engine_version":{"type":"string","title":"Engine Version"},"stage":{"type":"string","title":"Stage"},"stage_label":{"type":"string","title":"Stage Label"},"detail":{"type":"string","title":"Detail"}},"type":"object","required":["scan_id","at","profile","engine_version","stage","stage_label","detail"],"title":"RetestOut","description":"The scan that established an issue no longer reproduces."},"ScanCreate":{"properties":{"asset_ids":{"items":{"type":"string","format":"uuid"},"type":"array","minItems":1,"title":"Asset Ids"},"profile":{"$ref":"#/components/schemas/ScanProfile","default":"standard"},"attest_authorized":{"type":"boolean","title":"Attest Authorized","default":false},"deep_ack":{"type":"boolean","title":"Deep Ack","default":false},"auth_ack":{"type":"boolean","title":"Auth Ack","default":false},"pentest_ack":{"type":"boolean","title":"Pentest Ack","default":false}},"type":"object","required":["asset_ids"],"title":"ScanCreate"},"ScanDiffOut":{"properties":{"asset_id":{"type":"string","format":"uuid","title":"Asset Id"},"from_scan":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"From Scan"},"to_scan":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"To Scan"},"new":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"New"},"resolved":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Resolved"},"unchanged_count":{"type":"integer","title":"Unchanged Count"}},"type":"object","required":["asset_id","from_scan","to_scan","new","resolved","unchanged_count"],"title":"ScanDiffOut"},"ScanOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"profile":{"$ref":"#/components/schemas/ScanProfile"},"status":{"type":"string","title":"Status"},"progress":{"type":"integer","title":"Progress"},"engine_version":{"type":"string","title":"Engine Version"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"finished_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Finished At"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"asset_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Asset Ids"},"finding_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Finding Count"}},"type":"object","required":["id","profile","status","progress","engine_version","created_at"],"title":"ScanOut"},"ScanProfile":{"type":"string","enum":["light","standard","deep"],"title":"ScanProfile","description":"Light = recon + safe checks (no LLM). Standard = full OWASP + infra,\nvalidated. Deep = bounded exploitation (Phase 2; gated ack)."},"SignupRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","maxLength":200,"minLength":10,"title":"Password"},"company_name":{"type":"string","maxLength":200,"minLength":1,"title":"Company Name"},"accept_tos":{"type":"boolean","title":"Accept Tos"},"accept_aup":{"type":"boolean","title":"Accept Aup"},"accept_roe":{"type":"boolean","title":"Accept Roe"},"entitlement":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Entitlement"},"attribution":{"additionalProperties":{"type":"string"},"type":"object","title":"Attribution"}},"type":"object","required":["email","password","company_name","accept_tos","accept_aup","accept_roe"],"title":"SignupRequest"},"TeaserFinding":{"properties":{"title":{"type":"string","title":"Title"},"severity":{"type":"string","title":"Severity"},"category":{"type":"string","title":"Category"},"owasp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owasp"}},"type":"object","required":["title","severity","category","owasp"],"title":"TeaserFinding"},"TokenResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"token_type":{"type":"string","title":"Token Type","default":"bearer"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"tenant_id":{"type":"string","format":"uuid","title":"Tenant Id"},"role":{"$ref":"#/components/schemas/UserRole"}},"type":"object","required":["access_token","user_id","tenant_id","role"],"title":"TokenResponse"},"UserRole":{"type":"string","enum":["owner","member","read_only","platform_admin"],"title":"UserRole","description":"What a person may do.\n\nThe first three are tenant roles, ordered by power. ``PLATFORM_ADMIN`` is\nnot a tenant role at all: it is Infiqon staff, and it is the only role that\nmay read across tenants. It is deliberately unreachable from every\nself-service path — signup and invite acceptance both refuse it — so the\nonly way to mint one is ``python -m secqon_api.admin_cli``, run by someone\nwho already has the database."},"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"},"VerificationInstructions":{"properties":{"asset_id":{"type":"string","format":"uuid","title":"Asset Id"},"method":{"$ref":"#/components/schemas/VerificationMethod"},"token":{"type":"string","title":"Token"},"instruction":{"type":"string","title":"Instruction"},"dns_txt_value":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dns Txt Value"},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path"},"file_body":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Body"},"meta_tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Meta Tag"}},"type":"object","required":["asset_id","method","token","instruction"],"title":"VerificationInstructions"},"VerificationMethod":{"type":"string","enum":["dns_txt","hosted_file","meta_tag"],"title":"VerificationMethod"},"VerificationResult":{"properties":{"asset_id":{"type":"string","format":"uuid","title":"Asset Id"},"status":{"$ref":"#/components/schemas/VerificationStatus"},"detail":{"type":"string","title":"Detail"}},"type":"object","required":["asset_id","status","detail"],"title":"VerificationResult"},"VerificationStart":{"properties":{"method":{"$ref":"#/components/schemas/VerificationMethod"}},"type":"object","required":["method"],"title":"VerificationStart"},"VerificationStatus":{"type":"string","enum":["unverified","pending","verified","lapsed","failed"],"title":"VerificationStatus","description":"An asset in any state other than VERIFIED must never receive scan\ntraffic (safety invariant #1)."}}}}