{
    "schema": "https://saferpage.de/schemas/operator-api-access.v1",
    "generated_at": "2026-07-21T22:06:48+00:00",
    "summary": "Betreiber-Zugriffsmodell für SaferPage-APIs und Exporte mit Rollen, Scopes, Zugriffsstufen, Key-Rotation, Rate-Limits, Audit-Logs und sicherem Secret-Umgang.",
    "metrics": {
        "tier_count": 4,
        "scope_count": 8,
        "export_catalog_count": 9,
        "check_count": 5,
        "passed_check_count": 0,
        "planned_check_count": 5,
        "developer_quickstart_count": 4,
        "developer_launch_item_count": 6,
        "blocked_launch_claim_count": 4,
        "openapi_path_count": 6,
        "postman_request_count": 8
    },
    "access_tiers": [
        {
            "id": "public",
            "label": "Public Read",
            "audience": "Besucher und Suchmaschinen",
            "auth": "keine",
            "rate_limit": "Caching/CDN, nur öffentliche Reports",
            "allowed_scopes": [
                "reports.public:read",
                "schemas:read",
                "badges.public:read"
            ]
        },
        {
            "id": "operator_read",
            "label": "Operator Read",
            "audience": "Betreiber, Datenschutz, Audit",
            "auth": "API-Key oder OIDC",
            "rate_limit": "600 Requests/Stunde je Key",
            "allowed_scopes": [
                "reports:read",
                "portfolio:read",
                "evidence:read",
                "exports:read"
            ]
        },
        {
            "id": "operator_write",
            "label": "Operator Workflow",
            "audience": "Website-Betrieb und PrivacyOps",
            "auth": "API-Key mit HMAC oder OIDC",
            "rate_limit": "120 Schreibaktionen/Stunde je Key",
            "allowed_scopes": [
                "nachweise:write",
                "dispatch:write",
                "integrations:dry_run"
            ]
        },
        {
            "id": "admin",
            "label": "Admin Setup",
            "audience": "Programm-Verantwortung/IT",
            "auth": "OIDC + Admin-Rolle",
            "rate_limit": "manuell freizugeben",
            "allowed_scopes": [
                "keys:rotate",
                "integrations:manage",
                "portfolio:manage"
            ]
        }
    ],
    "scopes": [
        {
            "id": "reports.public:read",
            "purpose": "Kanonische Kurzreports und öffentliche Trust-Links lesen.",
            "risk": "niedrig",
            "default_tier": "public"
        },
        {
            "id": "schemas:read",
            "purpose": "Schema Registry und maschinenlesbare Vertragsformen lesen.",
            "risk": "niedrig",
            "default_tier": "public"
        },
        {
            "id": "reports:read",
            "purpose": "Domainberichte, Scorecards und Modul-Exports lesen.",
            "risk": "mittel",
            "default_tier": "operator_read"
        },
        {
            "id": "portfolio:read",
            "purpose": "Portfolio, Audit-Trail, Scanplan, Digest und Intake-Pakete lesen.",
            "risk": "mittel",
            "default_tier": "operator_read"
        },
        {
            "id": "evidence:read",
            "purpose": "Nachweise, Hash-Manifest und Scanbelege lesen.",
            "risk": "hoch",
            "default_tier": "operator_read"
        },
        {
            "id": "nachweise:write",
            "purpose": "Nachweispositionen in Zielsysteme übergeben.",
            "risk": "hoch",
            "default_tier": "operator_write"
        },
        {
            "id": "dispatch:write",
            "purpose": "Scan-Dispatches und Delivery-Jobs auslösen.",
            "risk": "hoch",
            "default_tier": "operator_write"
        },
        {
            "id": "keys:rotate",
            "purpose": "API-Key-Rotation und Sperrung verwalten.",
            "risk": "kritisch",
            "default_tier": "admin"
        }
    ],
    "export_catalog": [
        {
            "id": "competitive_matrix",
            "label": "Feature-Matrix",
            "url": "https://saferpage.de/vergleich/features-json",
            "scope": "schemas:read"
        },
        {
            "id": "portfolio_audit",
            "label": "Portfolio Audit Trail",
            "url": "https://saferpage.de/portfolio/audit-json",
            "scope": "portfolio:read"
        },
        {
            "id": "portfolio_schedule",
            "label": "Portfolio Scanplan",
            "url": "https://saferpage.de/portfolio/schedule-json",
            "scope": "portfolio:read"
        },
        {
            "id": "api_key_readiness",
            "label": "API-Key-Readiness",
            "url": "https://saferpage.de/api-zugriff/key-readiness-json",
            "scope": "keys:rotate"
        },
        {
            "id": "api_access_migration_sql",
            "label": "API-Access-Migration SQL",
            "url": "https://saferpage.de/api-zugriff/access-migration.sql",
            "scope": "keys:rotate"
        },
        {
            "id": "api_runtime_gate_probe",
            "label": "API Runtime Gate Probe",
            "url": "https://saferpage.de/api-zugriff/runtime-gate-probe-json",
            "scope": "keys:rotate"
        },
        {
            "id": "evidence_center",
            "label": "Nachweis-Center",
            "url": "https://saferpage.de/nachweise/anrufer.info/export",
            "scope": "evidence:read"
        },
        {
            "id": "nachweisposition_delivery",
            "label": "Nachweispositions-Delivery",
            "url": "https://saferpage.de/fix-guides/anrufer.info/tickets-delivery-json",
            "scope": "nachweise:write"
        },
        {
            "id": "integration_setup",
            "label": "Integrations-Setup",
            "url": "https://saferpage.de/integrationen/setup-json",
            "scope": "integrations:manage"
        }
    ],
    "key_lifecycle": {
        "prefix_format": "sp_live_<8 Zeichen Prefix>",
        "storage_policy": "Klartext-Key nur einmal beim Erstellen anzeigen; serverseitig nur Salt/Hash und Prefix speichern.",
        "rotation_days": 90,
        "emergency_revoke": "Key sofort sperren, aktive Sessions beenden, Integrations-Dry-Run erneut ausführen.",
        "least_privilege": "Keys nur für benötigte Domain-Gruppe, Scopes und Zielsysteme ausstellen."
    },
    "validation_checks": [
        {
            "id": "key_storage",
            "label": "API-Keys nur gehasht speichern",
            "status": "planned",
            "owner": "IT/Security",
            "evidence": "Nur Key-Prefix und Hash im Admin-Kontext; kein Klartext im Export."
        },
        {
            "id": "scope_enforcement",
            "label": "Scopes serverseitig erzwingen",
            "status": "planned",
            "owner": "Backend",
            "evidence": "Jeder Endpoint mappt auf mindestens einen Scope."
        },
        {
            "id": "rotation",
            "label": "Rotation und Ablaufdatum",
            "status": "planned",
            "owner": "Programm-Verantwortung",
            "evidence": "Maximale Key-Laufzeit 90 Tage, Notfall-Sperrung sofort."
        },
        {
            "id": "audit_log",
            "label": "Access Audit Log",
            "status": "planned",
            "owner": "Compliance/IT",
            "evidence": "Key-Prefix, Scope, Endpoint, Statuscode, Zeitstempel und Request-ID protokollieren."
        },
        {
            "id": "rate_limit",
            "label": "Rate-Limit je Key und Scope",
            "status": "planned",
            "owner": "Platform",
            "evidence": "Lesen, Schreiben und Admin getrennt limitieren."
        }
    ],
    "developer_launch_kit": {
        "status": "contract_ready_waiting_for_live_keys",
        "summary": "Developer-Experience für API-first Betreiber: Quickstarts, OpenAPI/Postman-Vertrag, SDK-Pfade, Sandbox, Webhook-Abnahme und Supportgrenzen sind öffentlich einordbar; echte Keys und Zielsysteme bleiben Go-live-Gates.",
        "quickstarts": [
            {
                "id": "curl_public_probe",
                "label": "curl Public Probe",
                "language": "curl",
                "scope": "reports.public:read",
                "secret_handling": "kein Key für Public-Read-Beispiel"
            },
            {
                "id": "node_operator_read",
                "label": "Node Operator Read",
                "language": "Node.js",
                "scope": "reports:read",
                "secret_handling": "Bearer-Key nur aus Server-Environment laden"
            },
            {
                "id": "php_export_client",
                "label": "PHP Export Client",
                "language": "PHP",
                "scope": "exports:read",
                "secret_handling": "Key nie in Querystring, Logs oder HTML ausgeben"
            },
            {
                "id": "python_hmac_write_fixture",
                "label": "Python HMAC Write Fixture",
                "language": "Python",
                "scope": "nachweise:write",
                "secret_handling": "HMAC-Secret nur serverseitig, negative Tests vor Live"
            }
        ],
        "launch_items": [
            {
                "id": "openapi_contract",
                "label": "OpenAPI-Vertrag",
                "status": "contract_ready_waiting_for_live_keys",
                "detail": "Bearer-Auth, Scopes, Rate-Limits, Fehlerobjekte, Request-ID und HMAC-Extension werden als Vertrag geführt."
            },
            {
                "id": "postman_smoke_collection",
                "label": "Postman/Smoke Collection",
                "status": "contract_ready_waiting_for_live_keys",
                "detail": "Public Probe, 401/403, HMAC-Negativtest, Revocation- und Rate-Limit-Faelle sind vor produktiven Keys testbar."
            },
            {
                "id": "sdk_readiness",
                "label": "SDK-Readiness",
                "status": "contract_ready_waiting_for_live_keys",
                "detail": "Node, PHP, Python, Go und CI/curl werden als Mindestpfade geführt; alle Beispiele laden Secrets nur serverseitig."
            },
            {
                "id": "sandbox_onboarding",
                "label": "Sandbox-Onboarding",
                "status": "dry_run_only",
                "detail": "Integratoren können gegen Public- und Deny-Fixtures entwickeln; produktive Operator-Keys bleiben blockiert."
            },
            {
                "id": "webhook_receiver_acceptance",
                "label": "Webhook-Receiver-Abnahme",
                "status": "required_before_write_live",
                "detail": "HMAC, Idempotency, Retry, minimierte Payloads und redacted Logs sind vor Write-Live Pflicht."
            },
            {
                "id": "support_target_boundary",
                "label": "Support-Ziel-Grenze",
                "status": "not_a_public_service_commitment",
                "detail": "Supportpfade werden als interne Abnahme geführt; keine öffentliche Servicezusage ohne Betreiber- und Vertragsfreigabe."
            }
        ],
        "blocked_claims": [
            "Keine produktive API-Key-Ausgabe ohne Key-Store, Pepper, Domain-Claim, Runtime-Gates und Betreiber-Signoff.",
            "Keine Write-/Webhook-Live-Zusage ohne HMAC-Secret, Idempotency, Receiver-Abnahme und Zielsystemfreigabe.",
            "Keine Service-, SDK- oder Sandbox-Garantie als öffentliches Angebot ohne freigegebenen Plan.",
            "Keine Roh-Keys, Hashes, DSN, Webhook-Ziel-URLs, Empfänger oder private Betreiberidentitäten in Public-Exports."
        ],
        "deep_dive_url": "https://saferpage.de/api-zugriff/key-readiness",
        "readiness_json_url": "https://saferpage.de/api-zugriff/key-readiness-json",
        "openapi_url": "https://saferpage.de/api-zugriff/openapi-json",
        "postman_url": "https://saferpage.de/api-zugriff/postman-json",
        "smoke_url": "https://saferpage.de/evidence/api-key-readiness-smoke.json",
        "claim_boundary": "Launch-Kit ist Developer-Readiness und kein produktiver API-Key-Zugang, keine Servicezusage, keine SDK-Garantie und keine Write-Live-Freigabe."
    },
    "openapi_contract": {
        "status": "no_secret_contract_ready",
        "url": "https://saferpage.de/api-zugriff/openapi-json",
        "path_count": 6,
        "paths": {
            "/api/scan": {
                "path": "/api/scan",
                "method": "get",
                "scope": "reports.public:read",
                "auth": "optional",
                "summary": "Kostenlosen Mini-Check starten. mode=full ist zahlungspflichtig und wird auf den Checkout verwiesen."
            },
            "/api/recent": {
                "path": "/api/recent",
                "method": "get",
                "scope": "reports.public:read",
                "auth": "optional",
                "summary": "Zuletzt geprüfte öffentliche Domains lesen."
            },
            "/api/crawler/status": {
                "path": "/api/crawler/status",
                "method": "get",
                "scope": "reports.public:read",
                "auth": "optional",
                "summary": "Öffentlichen Crawler-Status lesen."
            },
            "/api/report": {
                "path": "/api/report",
                "method": "get",
                "scope": "reports.public:read",
                "auth": "optional",
                "summary": "Maschinenlesbaren Report eines Full-Checks lesen; Mini-Checks liefern HTTP 402."
            },
            "/api/report/export": {
                "path": "/api/report/export",
                "method": "get",
                "scope": "exports:read",
                "auth": "bearer",
                "summary": "Full-Check-Export im freigegebenen Format abrufen; Mini-Checks sind nicht exportierbar."
            },
            "/api/operator/probe": {
                "path": "/api/operator/probe",
                "method": "get",
                "scope": "keys:rotate",
                "auth": "bearer",
                "summary": "Operator-API-Gate, Deny-Verhalten und Audit-Evidence prüfen."
            }
        },
        "claim_boundary": "OpenAPI beschreibt öffentliche und geschützte Vertragsflächen, stellt aber keine produktiven API-Keys und keine Servicezusage bereit."
    },
    "postman_collection_contract": {
        "status": "no_secret_collection_ready",
        "url": "https://saferpage.de/api-zugriff/postman-json",
        "request_count": 8,
        "requests": [
            {
                "id": "public_scan_probe",
                "label": "Public Mini Scan Probe",
                "method": "GET",
                "path": "/api/scan",
                "query": {
                    "url": "example.de",
                    "mode": "mini"
                },
                "scope": "reports.public:read",
                "auth": "none",
                "expected_status": [
                    200
                ],
                "purpose": "Öffentlichen Mini-Check ohne Key testen; mini ist auch ohne mode der Standard."
            },
            {
                "id": "public_full_scan_probe",
                "label": "Full-Check Payment Gate Probe",
                "method": "GET",
                "path": "/api/scan",
                "query": {
                    "url": "example.de",
                    "mode": "full"
                },
                "scope": "reports.public:read",
                "auth": "none",
                "expected_status": [
                    402
                ],
                "purpose": "Prüfen, dass ein Full-Check ohne bestätigte Zahlung nicht gestartet wird und der Checkout-Pfad zurückgegeben wird."
            },
            {
                "id": "recent_public",
                "label": "Recent Public Reports",
                "method": "GET",
                "path": "/api/recent",
                "query": [],
                "scope": "reports.public:read",
                "auth": "none",
                "expected_status": [
                    200
                ],
                "purpose": "Zuletzt geprüfte öffentliche Domains lesen."
            },
            {
                "id": "crawler_status_public",
                "label": "Crawler Status Public",
                "method": "GET",
                "path": "/api/crawler/status",
                "query": [],
                "scope": "reports.public:read",
                "auth": "none",
                "expected_status": [
                    200
                ],
                "purpose": "Crawler-Transparenz für Betreiber prüfen."
            },
            {
                "id": "report_public_read",
                "label": "Full Report Read",
                "method": "GET",
                "path": "/api/report",
                "query": {
                    "id": "<full-scan-id>"
                },
                "scope": "reports.public:read",
                "auth": "none",
                "expected_status": [
                    200,
                    402,
                    404
                ],
                "purpose": "Maschinenlesbaren Full-Check abrufen und Mini-Check-Exportgrenze prüfen."
            },
            {
                "id": "operator_probe_missing_auth",
                "label": "Operator Probe ohne Authorization",
                "method": "GET",
                "path": "/api/operator/probe",
                "query": [],
                "scope": "keys:rotate",
                "auth": "none",
                "expected_status": [
                    401
                ],
                "purpose": "Deny-Verhalten ohne Bearer-Key absichern."
            },
            {
                "id": "operator_probe_bearer_placeholder",
                "label": "Operator Probe mit Bearer Placeholder",
                "method": "GET",
                "path": "/api/operator/probe",
                "query": [],
                "scope": "keys:rotate",
                "auth": "bearer_placeholder",
                "expected_status": [
                    200,
                    403
                ],
                "purpose": "Protected Contract mit serverseitig gesetztem Placeholder-Key testen."
            },
            {
                "id": "report_export_bearer_placeholder",
                "label": "Full-Check-Export mit Bearer Placeholder",
                "method": "GET",
                "path": "/api/report/export",
                "query": {
                    "id": "<full-scan-id>",
                    "format": "json"
                },
                "scope": "exports:read",
                "auth": "bearer_placeholder",
                "expected_status": [
                    200,
                    402,
                    403,
                    404
                ],
                "purpose": "Full-Check-Exportvertrag und Mini-Check-Zahlungsschranke prüfen."
            }
        ],
        "claim_boundary": "No-Secret-Postman Collection als Dry-run-/Smoke-Vertrag mit Placeholdern. Sie enthält keine echten Keys, keine privaten Ziel-URLs, keine Empfänger und keine Servicezusage."
    },
    "example_headers": {
        "Authorization": "Bearer sp_live_<redacted>",
        "X-SaferPage-Key-Prefix": "sp_live_ab12cd34",
        "X-SaferPage-Request-Id": "req_<uuid>",
        "X-SaferPage-Signature": "sha256=<HMAC für Schreib-/Webhook-Aufrufe>"
    },
    "links": {
        "html": "https://saferpage.de/api-zugriff",
        "json": "https://saferpage.de/api-zugriff/export",
        "csv": "https://saferpage.de/api-zugriff/export-csv",
        "markdown": "https://saferpage.de/api-zugriff/runbook-md",
        "openapi": "https://saferpage.de/api-zugriff/openapi-json",
        "postman": "https://saferpage.de/api-zugriff/postman-json",
        "key_readiness": "https://saferpage.de/api-zugriff/key-readiness-json",
        "runtime_gate_probe": "https://saferpage.de/api-zugriff/runtime-gate-probe-json",
        "migration_sql": "https://saferpage.de/api-zugriff/access-migration.sql",
        "schemas": "https://saferpage.de/schemas",
        "integrations": "https://saferpage.de/integrationen",
        "comparison": "https://saferpage.de/vergleich"
    },
    "disclaimer": "Dieses Paket beschreibt Zugriffsstufen und Sicherheitsanforderungen. Es erzeugt keine echten API-Keys und zeigt keine Secrets."
}
