{
    "openapi": "3.0.3",
    "info": {
        "title": "nebty API",
        "version": "1.0.0",
        "description": "Read access to your brand-protection data in nebty: the brands being monitored, the domains found impersonating them, the scan results behind each finding and your takedown cases. You can also request a takedown.\n\n**Base URL:** `https://app.nebty.de`\n\n**Authentication.** Send your API key in the `Authorization` header as `Authorization: Api-Key <key>`. A key acts as the user it belongs to, and results are limited to what that user may see: the brands the user is a member of, and takedowns the user requested or that belong to one of those brands. Records you cannot see are treated as if they did not exist.\n\n**Identifiers** are UUIDs.\n\n**Pagination.** List endpoints are page-number paginated. Pass `page` (1-based) and `page_size`. The default page size is 50 and the maximum is 100. A paginated response is an object with `count` (total rows), `next` and `previous` (URLs or `null`) and `results`; the total is also sent in the `X-Total-Count` response header. Keep `page_size` and all filters unchanged while walking through pages.\n\n**Compact rows.** The brand list and the per-brand domain and scan lists accept `compact=true` and then return a short summary per row instead of the full record with embedded scan history. Use it for lists and fetch a single domain for the full evidence. It is much lighter for large brands.\n\n**Undocumented fields.** Responses can contain additional fields that are not documented here. They are not part of the public contract and can change or disappear without notice."
    },
    "paths": {
        "/core/api/brands/": {
            "get": {
                "operationId": "listBrands",
                "description": "Returns the brands the API key's user is a member of, ordered by name (case-insensitive).\n\nPaginated: `page` and `page_size` (default 50, maximum 100). See the pagination note in the API description.\n\nQuery parameters:\n\n* `compact=true` returns a short row per brand (`id`, `name`, `domain`, `plan`, `monitoring_enabled`, `brand_markets`) and is the recommended form for listing.\n* `include_stats=true` (or `1`) adds headline figures to each full brand row: domain and scan counts, latest scan date, high-risk count, average risk score and the risk, verdict and HTTP-status breakdowns. It has no effect with `compact=true`.",
                "parameters": [
                    {
                        "in": "query",
                        "name": "compact",
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Return compact list summaries without embedded history. Use domain detail for evidence."
                    },
                    {
                        "name": "page",
                        "required": false,
                        "in": "query",
                        "description": "A page number within the paginated result set.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "page_size",
                        "required": false,
                        "in": "query",
                        "description": "Number of results to return per page.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "tags": [
                    "Brands"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PaginatedBrandListItemList"
                                }
                            }
                        },
                        "description": ""
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "List brands"
            }
        },
        "/core/api/brands/{id}/": {
            "get": {
                "operationId": "getBrand",
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "UUID of the brand, as returned in the `id` field of the brand list.",
                        "required": true
                    }
                ],
                "tags": [
                    "Brands"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Brand"
                                }
                            }
                        },
                        "description": ""
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "Get a brand",
                "description": "Returns one brand: name, domain, plan, monitoring settings, keywords, trusted domains and the API key's user's role in it (`my_role`). Answers `404` if the brand does not exist or the user is not a member of it."
            }
        },
        "/core/api/brands/{id}/domains/": {
            "get": {
                "operationId": "listBrandDomains",
                "description": "Returns the domains associated with a brand, with filtering and sorting. `risk_score` and `verdict` describe the pairing of this brand with the domain, not the domain on its own. The default order is highest risk first.\n\nPaginated: `page` and `page_size` (default 50, maximum 100). See the pagination note in the API description.\n\nUse `compact=true` for a short row per domain (`id`, `name`, `source`, a compact `latest_scan` and `open_takedown`). Without it every row embeds scan history and is much larger; fetch a single domain when you need the evidence.\n\nFilters: `domain_filter` (case-insensitive substring of the name), `http_status_filter` (`online`, `offline`, `all`), `risk_score_filter` (`low`, `medium`, `high`, `all`), `verdict_filter` (`red`, `amber`, `green`, `unknown`, `all`) and `triage_filter`. `visual_match_filter` is deprecated; use `verdict_filter`. Sort with `sort_field` and `sort_direction`. `group_by=apex` returns one row per registrable domain, with its subdomains collapsed, instead of one row per domain. An unsupported `group_by` or `triage_filter` value is rejected with `400`.",
                "parameters": [
                    {
                        "in": "query",
                        "name": "compact",
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Return compact list summaries without embedded history. Use domain detail for evidence."
                    },
                    {
                        "in": "query",
                        "name": "dismissed_filter",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "hide",
                                "only"
                            ]
                        },
                        "description": "Filter by the 'Not relevant' mark this brand set on the domain (POST /brands/{id}/domains/{domain_id}/set-dismissed/). 'hide' leaves marked domains out, 'only' lists just them, 'all' (default) lists both, exactly as before the mark existed. The mark never changes the risk score: the statistics' domain_risk_distribution still counts marked domains; domain_review_count does not."
                    },
                    {
                        "in": "query",
                        "name": "domain_filter",
                        "schema": {
                            "type": "string"
                        },
                        "description": "Filter domains by name (case-insensitive substring match)"
                    },
                    {
                        "in": "query",
                        "name": "group_by",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "apex",
                                "none"
                            ]
                        },
                        "description": "Collapse the list to one row per registrable apex (eTLD+1) so a third-party domain and all its subdomains take one decision. Applied after every filter. With 'apex' the response items are BrandDomainApexGroup objects, not Domain objects, and the paginated `count` is the number of apexes — summing `domain_count` over all pages reproduces the ungrouped total for the same filter. Default 'none'."
                    },
                    {
                        "in": "query",
                        "name": "http_status_filter",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "offline",
                                "online"
                            ]
                        },
                        "description": "Filter by HTTP status: 'online', 'offline', or 'all'"
                    },
                    {
                        "in": "path",
                        "name": "id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "UUID of the brand, as returned in the `id` field of the brand list.",
                        "required": true
                    },
                    {
                        "in": "query",
                        "name": "page",
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Page number within the paginated result set."
                    },
                    {
                        "in": "query",
                        "name": "page_size",
                        "schema": {
                            "type": "integer"
                        },
                        "description": "Rows per page. Defaults to 50; clamped to 100 above that."
                    },
                    {
                        "in": "query",
                        "name": "risk_score_filter",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "high",
                                "low",
                                "medium"
                            ]
                        },
                        "description": "Filter by risk score level: 'low', 'medium', 'high', or 'all'"
                    },
                    {
                        "in": "query",
                        "name": "sort_direction",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "asc",
                                "desc"
                            ]
                        },
                        "description": "Sort direction"
                    },
                    {
                        "in": "query",
                        "name": "sort_field",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "domain",
                                "http_status",
                                "review_priority",
                                "risk_score",
                                "visual_match"
                            ]
                        },
                        "description": "Field to sort by. 'review_priority' is the layer-2 pre-ranking of what a human still has to review; unranked pairs sort below every ranked one, with risk breaking ties. Under group_by=apex only 'domain' (apex name) and 'risk_score' (the group's worst host) apply."
                    },
                    {
                        "in": "query",
                        "name": "triage_filter",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "escalated",
                                "filed",
                                "queue"
                            ]
                        },
                        "description": "Filter by the common-word triage outcome, for brands where it is enabled. 'queue' hides the pairs the machine filed as an unrelated entity or a name collision — the review worklist. 'filed' shows only those, for auditing what was hidden. 'escalated' shows only pairs carrying a brand-affinity token. Pairs a human has judged are never hidden by this filter and never listed as machine decisions. Default 'all', which returns every row. Note that the brand statistics endpoints (`/stats/` and `?include_stats=true`) always describe the 'queue' population, so `verdict_stats` matches the row count under 'queue' rather than under 'all'."
                    },
                    {
                        "in": "query",
                        "name": "verdict_filter",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "amber",
                                "green",
                                "red",
                                "unknown"
                            ]
                        },
                        "description": "Filter by the merged customer-facing verdict for this brand's pair with the domain. Accepts the same values as BrandStatsSerializer.verdict_stats' keys, plus 'all' — a stat and its filtered list can never disagree."
                    },
                    {
                        "in": "query",
                        "name": "visual_match_filter",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "all",
                                "no",
                                "unknown",
                                "yes"
                            ]
                        },
                        "description": "DEPRECATED — use verdict_filter. Filter by visual match: 'yes', 'no', 'unknown', or 'all'. Kept so the frontend does not break on deploy; the visual scan is now one of two inputs to the merged verdict, not the customer-facing answer.",
                        "deprecated": true
                    }
                ],
                "tags": [
                    "Domains"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PaginatedBrandDomainListItemList"
                                }
                            }
                        },
                        "description": ""
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid query parameters or request data. Field errors appear directly on the response; malformed JSON has a detail message.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/ApiErrorResponse"
                                        },
                                        {
                                            "$ref": "#/components/schemas/FieldValidationError"
                                        }
                                    ]
                                }
                            }
                        }
                    }
                },
                "summary": "List a brand's domains"
            }
        },
        "/core/api/brands/{id}/domains/{domain_id}/": {
            "get": {
                "operationId": "getBrandDomain",
                "description": "Returns one domain associated with the brand, in the full form with scan history and evidence. It is the same record as a row of the non-compact domain list, with the same brand-specific risk score and verdict. Answers `404` if the id is not a UUID or the domain is not associated with this brand.",
                "parameters": [
                    {
                        "in": "path",
                        "name": "domain_id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "UUID of a domain associated with this brand (as returned in the `id` field of the brand's domain list).",
                        "required": true
                    },
                    {
                        "in": "path",
                        "name": "id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "UUID of the brand, as returned in the `id` field of the brand list.",
                        "required": true
                    }
                ],
                "tags": [
                    "Domains"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Domain"
                                }
                            }
                        },
                        "description": ""
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "Get a brand's domain"
            }
        },
        "/core/api/brands/{id}/scans/": {
            "get": {
                "operationId": "listBrandScans",
                "description": "Returns scan results for all domains associated with the brand, newest first. A domain scanned several times appears several times; use the domain endpoints for the current state of one domain.\n\nPaginated: `page` and `page_size` (default 50, maximum 100). See the pagination note in the API description.\n\nUse `compact=true` for a short row per scan (`id`, `domain`, `domain_name`, `risk_score`, `verdict`, `requires_human_review`, `https_head_request_response_code` and timestamps). Without it each row embeds the scan's history and evidence.",
                "parameters": [
                    {
                        "in": "query",
                        "name": "compact",
                        "schema": {
                            "type": "boolean"
                        },
                        "description": "Return compact list summaries without embedded history. Use domain detail for evidence."
                    },
                    {
                        "in": "path",
                        "name": "id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "UUID of the brand, as returned in the `id` field of the brand list.",
                        "required": true
                    },
                    {
                        "name": "page",
                        "required": false,
                        "in": "query",
                        "description": "A page number within the paginated result set.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "page_size",
                        "required": false,
                        "in": "query",
                        "description": "Number of results to return per page.",
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "tags": [
                    "Scans"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PaginatedBrandScanListItemList"
                                }
                            }
                        },
                        "description": ""
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "List a brand's scans"
            }
        },
        "/core/api/brands/{id}/stats/": {
            "get": {
                "operationId": "getBrandStats",
                "description": "Returns aggregate figures for one brand: domain count, scan count, date of the latest scan, high-risk count, average risk score, `risk_distribution`, `domain_risk_distribution` (domain buckets that sum to `domain_count`; prefer it over the legacy `risk_distribution`), `verdict_stats` (`red`, `amber`, `green`, `unknown` counts, the same values `verdict_filter` accepts on the domain list) and `http_status_stats`.\n\n`visual_match_stats` is deprecated; use `verdict_stats`. The figures are cached for up to five minutes, so a newly found domain can take that long to show up here.",
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "UUID of the brand, as returned in the `id` field of the brand list.",
                        "required": true
                    }
                ],
                "tags": [
                    "Brands"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/BrandStats"
                                }
                            }
                        },
                        "description": ""
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "Get brand statistics"
            }
        },
        "/core/api/takedowns/": {
            "get": {
                "operationId": "listTakedowns",
                "description": "Returns the takedown cases the API key's user can see: those they requested and those belonging to a brand they are a member of. Newest first.\n\nFilters: `brand` (UUID), `status`, `resolution`, `created_after` (inclusive) and `created_before` (exclusive), both ISO 8601. Invalid values, and `created_after` not earlier than `created_before`, are rejected with `400`.\n\nPaginated: `page` and `page_size` (default 50). On this endpoint a `page_size` above 100 is rejected with `400` rather than reduced.\n\nA takedown's `status` is one of `REQUESTED` (not yet started), `OPEN`, `IN_PROGRESS`, `PENDING_RESPONSE`, `CLOSED`, `FAILED` or `REJECTED`. `CLOSED` alone does not mean the site was taken down; read `resolution` for the outcome. `price` and `price_currency` are the price per successful takedown (net, VAT on top) agreed when the takedown was ordered, or `null` and empty when none was agreed at order.",
                "parameters": [
                    {
                        "in": "query",
                        "name": "brand",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "Filter takedowns for a specific brand ID"
                    },
                    {
                        "in": "query",
                        "name": "category",
                        "schema": {
                            "enum": [
                                "website",
                                "token"
                            ],
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "What the case is against: website, or token (a fake crypto token).\n\n* `website` - Website\n* `token` - Token"
                    },
                    {
                        "in": "query",
                        "name": "created_after",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        },
                        "description": "Created at or after this ISO 8601 timestamp (inclusive)."
                    },
                    {
                        "in": "query",
                        "name": "created_before",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        },
                        "description": "Created before this ISO 8601 timestamp (exclusive)."
                    },
                    {
                        "name": "page",
                        "required": false,
                        "in": "query",
                        "description": "A page number within the paginated result set.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "in": "query",
                        "name": "page_size",
                        "schema": {
                            "type": "integer",
                            "maximum": 100,
                            "minimum": 1
                        },
                        "description": "Items per page, 1–100; default 50. Keep this value unchanged while paging."
                    },
                    {
                        "in": "query",
                        "name": "resolution",
                        "schema": {
                            "enum": [
                                "DOMAIN_SUSPENDED",
                                "CONTENT_REMOVED",
                                "SERVER_HOLD",
                                "VOLUNTARY_TAKEDOWN",
                                "UNRESOLVED",
                                "FALSE_POSITIVE",
                                "TOKEN_LISTING_REMOVED",
                                "TOKEN_TRADING_BLOCKED",
                                "TOKEN_WARNING_ADDED"
                            ],
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "Exact outcome. CLOSED alone does not mean successful removal.\n\n* `DOMAIN_SUSPENDED` - Domain Suspended\n* `CONTENT_REMOVED` - Content Removed\n* `SERVER_HOLD` - Server Hold\n* `VOLUNTARY_TAKEDOWN` - Voluntary Takedown\n* `UNRESOLVED` - Unresolved\n* `FALSE_POSITIVE` - False Positive\n* `TOKEN_LISTING_REMOVED` - Agreed token listing removed\n* `TOKEN_TRADING_BLOCKED` - Trading blocked on agreed platform\n* `TOKEN_WARNING_ADDED` - Token warning added (partial mitigation)"
                    },
                    {
                        "in": "query",
                        "name": "status",
                        "schema": {
                            "enum": [
                                "REQUESTED",
                                "OPEN",
                                "IN_PROGRESS",
                                "PENDING_RESPONSE",
                                "CLOSED",
                                "FAILED",
                                "REJECTED"
                            ],
                            "type": "string",
                            "minLength": 1
                        },
                        "description": "* `REQUESTED` - Pending review\n* `OPEN` - Open\n* `IN_PROGRESS` - In Progress\n* `PENDING_RESPONSE` - Pending Response\n* `CLOSED` - Closed\n* `FAILED` - Failed\n* `REJECTED` - Rejected"
                    }
                ],
                "tags": [
                    "Takedowns"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PaginatedTakedownList"
                                }
                            }
                        },
                        "description": ""
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid query parameters or request data. Field errors appear directly on the response; malformed JSON has a detail message.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/ApiErrorResponse"
                                        },
                                        {
                                            "$ref": "#/components/schemas/FieldValidationError"
                                        }
                                    ]
                                }
                            }
                        }
                    }
                },
                "summary": "List takedowns"
            },
            "post": {
                "operationId": "createTakedown",
                "description": "Requests a takedown of a website. Send `target_website` (an `http` or `https` URL on a public host; `localhost` and non-public IP addresses are rejected) and optionally `brand` (UUID) and `user_comment`.\n\nIf you pass `brand`, the API key's user must be a member of it, otherwise the request is rejected with `400`. Once nebty enforces the price consent, a user who is a member of a brand that takes it must pass `brand`; without it the request is rejected with `400` and `code: brand_required`.\n\nThe new takedown starts as `OPEN` or as `REQUESTED` (not yet started; nebty checks it first and then moves it to `OPEN`, or to `REJECTED`). Read `status` in the `201` response; do not assume either.\n\n**Price consent.** For some brands an order is billed at a price per successful takedown that the person ordering must accept. Then send the accepted price as `accepted_price` (decimal string, net, VAT on top) and `accepted_currency` (`EUR`, `USD` or `CAD`), both or neither. Sending them is a binding order at that price: show the price to a person and let them accept it before you send it, and never fill it in from an error response by itself. A price that no longer matches is rejected with `409` and `code: price_changed`; once nebty enforces the consent, an order without it is rejected with `400` and `code: price_consent_required`. Both bodies carry the current price as `price: {amount, currency}`. For brands that take no price consent, sending the fields is rejected with `400` and `code: price_not_applicable`; leave them out. The accepted price is returned as `price` and `price_currency` on the takedown, and nebty mails the requesting user a confirmation of the order with the price and the next step.\n\n**One active case per website.** If the brand (or, without `brand`, the API key's user) already has an active takedown (`REQUESTED`, `OPEN`, `IN_PROGRESS` or `PENDING_RESPONSE`) for the same host, the request is rejected with `409`, `code: duplicate` and the existing case's id as `takedown_id`. The host is compared without case and a leading `www.`; a subdomain is another host. Nothing is created or billed.\n\nOnce nebty enforces the signed Power of Attorney, also send `authorization_consent: true` (you confirm you are authorized to request the takedown for the brand), and the brand needs an active signed Power of Attorney. Without one the request is rejected with `400` and `code: poa_required`; a brand admin grants it in the nebty dashboard. Until then the field is accepted and ignored.",
                "tags": [
                    "Takedowns"
                ],
                "requestBody": {
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/TakedownCreate"
                            }
                        },
                        "application/x-www-form-urlencoded": {
                            "schema": {
                                "$ref": "#/components/schemas/TakedownCreate"
                            }
                        },
                        "multipart/form-data": {
                            "schema": {
                                "$ref": "#/components/schemas/TakedownCreate"
                            }
                        }
                    },
                    "required": true
                },
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "201": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Takedown"
                                }
                            }
                        },
                        "description": ""
                    },
                    "400": {
                        "description": "Invalid request data (field errors directly on the response), a refused order with a `code` (`poa_required`, `brand_required`, `price_not_applicable`), or `code: price_consent_required` with the current `price`.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/ApiErrorResponse"
                                        },
                                        {
                                            "$ref": "#/components/schemas/FieldValidationError"
                                        },
                                        {
                                            "$ref": "#/components/schemas/PriceConsentError"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "409": {
                        "description": "`code: price_changed`: the `accepted_price` no longer matches. The body carries the current price as `price: {amount, currency}`; show it to the person ordering and order again. `code: poa_not_approved` (staff keys only): the brand's Power of Attorney is still under review. `code: duplicate`: an active takedown for this host exists; `takedown_id` is its id.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/ApiErrorResponse"
                                        },
                                        {
                                            "$ref": "#/components/schemas/PriceConsentError"
                                        },
                                        {
                                            "$ref": "#/components/schemas/DuplicateTakedownError"
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "Request a takedown"
            }
        },
        "/core/api/takedowns/{id}/": {
            "get": {
                "operationId": "getTakedown",
                "description": "Returns one takedown case with its abuse contacts and blacklist submissions. Answers `404` if the takedown does not exist or the API key's user can neither see it as its requester nor through a brand membership.",
                "parameters": [
                    {
                        "in": "path",
                        "name": "id",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "description": "UUID of the takedown.",
                        "required": true
                    }
                ],
                "tags": [
                    "Takedowns"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Takedown"
                                }
                            }
                        },
                        "description": ""
                    },
                    "404": {
                        "description": "The requested page or record does not exist or cannot be accessed.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid query parameters or request data. Field errors appear directly on the response; malformed JSON has a detail message.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "anyOf": [
                                        {
                                            "$ref": "#/components/schemas/ApiErrorResponse"
                                        },
                                        {
                                            "$ref": "#/components/schemas/FieldValidationError"
                                        }
                                    ]
                                }
                            }
                        }
                    }
                },
                "summary": "Get a takedown"
            }
        },
        "/core/api/takedowns/{takedown_pk}/events/": {
            "get": {
                "operationId": "listTakedownEvents",
                "description": "Returns the event log of a takedown (status changes, notes and other recorded steps), newest first.\n\nPaginated: `page` and `page_size` (default 50, maximum 100). See the pagination note in the API description.\n\nIf the takedown does not exist or is not visible to the API key's user, the result is an empty list, not `404`.",
                "parameters": [
                    {
                        "name": "page",
                        "required": false,
                        "in": "query",
                        "description": "A page number within the paginated result set.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "page_size",
                        "required": false,
                        "in": "query",
                        "description": "Number of results to return per page.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "in": "path",
                        "name": "takedown_pk",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "required": true,
                        "description": "UUID of the takedown."
                    }
                ],
                "tags": [
                    "Takedowns"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/PaginatedTakedownEventList"
                                }
                            }
                        },
                        "description": ""
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "404": {
                        "description": "The requested page does not exist. An unknown or inaccessible takedown returns an empty list with 200 instead.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "List a takedown's events"
            }
        },
        "/core/api/users/profile/": {
            "get": {
                "operationId": "getProfile",
                "description": "Returns the profile of the user the API key belongs to: id, username, email, account type, plan and two-factor state. A `200` also confirms that the key is valid and active.",
                "tags": [
                    "Account"
                ],
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "responses": {
                    "200": {
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/UserProfile"
                                }
                            }
                        },
                        "description": ""
                    },
                    "401": {
                        "description": "The API key is missing, invalid, revoked or belongs to an inactive user.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    },
                    "429": {
                        "description": "Too many requests or failed authentication attempts. Try again later.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/ApiErrorResponse"
                                }
                            }
                        }
                    }
                },
                "summary": "Get the current user"
            }
        }
    },
    "components": {
        "schemas": {
            "AbuseContact": {
                "type": "object",
                "description": "Serializer for abuse contact details.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "contact_type": {
                        "$ref": "#/components/schemas/AbuseContactTypeEnum"
                    },
                    "contact_type_display": {
                        "type": "string",
                        "readOnly": true
                    },
                    "provider_name": {
                        "type": "string",
                        "description": "Provider name, e.g. 'Cloudflare', 'Openprovider'",
                        "maxLength": 255
                    },
                    "abuse_email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true,
                        "description": "Abuse email address.",
                        "maxLength": 254
                    },
                    "abuse_form_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "description": "URL to abuse report form.",
                        "maxLength": 200
                    },
                    "report_status": {
                        "$ref": "#/components/schemas/AbuseReportStatusEnum"
                    },
                    "report_status_display": {
                        "type": "string",
                        "readOnly": true
                    },
                    "reported_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "response_received_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "case_reference": {
                        "type": "string",
                        "nullable": true,
                        "description": "Provider case reference, e.g. 'Case 00954977'",
                        "maxLength": 255
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "contact_type",
                    "contact_type_display",
                    "created_at",
                    "id",
                    "provider_name",
                    "report_status_display",
                    "updated_at"
                ]
            },
            "AbuseContactTypeEnum": {
                "enum": [
                    "REGISTRAR",
                    "HOSTING",
                    "CDN",
                    "BACKEND",
                    "REGISTRY",
                    "OTHER"
                ],
                "type": "string",
                "description": "* `REGISTRAR` - Registrar\n* `HOSTING` - Hosting Provider\n* `CDN` - CDN / Proxy\n* `BACKEND` - Backend Service\n* `REGISTRY` - Domain Registry\n* `OTHER` - Other"
            },
            "AbuseReportStatusEnum": {
                "enum": [
                    "NOT_SENT",
                    "SENT",
                    "ACKNOWLEDGED",
                    "ACTION_TAKEN",
                    "REJECTED",
                    "NO_RESPONSE"
                ],
                "type": "string",
                "description": "* `NOT_SENT` - Not Sent\n* `SENT` - Sent\n* `ACKNOWLEDGED` - Acknowledged\n* `ACTION_TAKEN` - Action Taken\n* `REJECTED` - Rejected\n* `NO_RESPONSE` - No Response"
            },
            "AccountTypeEnum": {
                "enum": [
                    "standard",
                    "partner",
                    "enterprise"
                ],
                "type": "string",
                "description": "* `standard` - Standard\n* `partner` - Partner\n* `enterprise` - Enterprise"
            },
            "ApiErrorResponse": {
                "type": "object",
                "properties": {
                    "detail": {
                        "type": "string"
                    }
                },
                "required": [
                    "detail"
                ]
            },
            "BlacklistSubmission": {
                "type": "object",
                "description": "Serializer for blacklist submission details.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "tier": {
                        "$ref": "#/components/schemas/TierEnum"
                    },
                    "tier_display": {
                        "type": "string",
                        "readOnly": true
                    },
                    "service_name": {
                        "type": "string",
                        "description": "Blacklist service name, e.g. 'Google Safe Browsing', 'Spamhaus'",
                        "maxLength": 255
                    },
                    "submission_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "description": "URL for submission.",
                        "maxLength": 200
                    },
                    "status": {
                        "$ref": "#/components/schemas/BlacklistSubmissionStatusEnum"
                    },
                    "status_display": {
                        "type": "string",
                        "readOnly": true
                    },
                    "submitted_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "confirmed_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When listing was confirmed."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "created_at",
                    "id",
                    "service_name",
                    "status_display",
                    "tier",
                    "tier_display",
                    "updated_at"
                ]
            },
            "BlacklistSubmissionStatusEnum": {
                "enum": [
                    "PENDING",
                    "SUBMITTED",
                    "LISTED",
                    "REJECTED"
                ],
                "type": "string",
                "description": "* `PENDING` - Pending\n* `SUBMITTED` - Submitted\n* `LISTED` - Listed\n* `REJECTED` - Rejected"
            },
            "BlankEnum": {
                "enum": [
                    ""
                ]
            },
            "Brand": {
                "type": "object",
                "description": "A monitored brand and its customer-editable monitoring configuration.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "domain": {
                        "type": "string",
                        "description": "The domain of the brand.",
                        "maxLength": 255
                    },
                    "trusted_domains": {
                        "type": "array",
                        "items": {},
                        "description": "Return trusted domain names, using prefetch cache when available.",
                        "readOnly": true
                    },
                    "all_keywords": {
                        "type": "array",
                        "items": {},
                        "readOnly": true
                    },
                    "negative_keywords": {
                        "type": "string",
                        "nullable": true,
                        "description": "Newline-separated terms to exclude from generated variations and domain matches for this brand. Replaces negative_variations and negative_domain_keywords, which are now read-only."
                    },
                    "seat_limit": {
                        "type": "integer",
                        "nullable": true,
                        "readOnly": true
                    },
                    "seats_used": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "my_role": {
                        "type": "string",
                        "nullable": true,
                        "readOnly": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "name": {
                        "type": "string",
                        "description": "The name of the brand, e.g. 'Cashlink'.",
                        "maxLength": 255
                    },
                    "has_own_website": {
                        "type": "boolean",
                        "readOnly": true,
                        "description": "Whether the customer has a website of their own. When False, `domain` holds a derived .invalid sentinel that anchors similarity scoring but is NOT treated as an identity term."
                    },
                    "plan": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/PlanEnum"
                            }
                        ],
                        "readOnly": true,
                        "description": "Per-brand subscription tier. Determines seat limit and write capability for members without a multi-brand AccountType. See docs/subscription-plans.md.\n\n* `free` - Free\n* `basic` - Basic\n* `business` - Business\n* `unlimited` - Unlimited"
                    },
                    "last_variation_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When was the last variation of the domain generated?"
                    },
                    "negative_variations": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Negative keywords separated by newlines. Variations containing these keywords will be removed."
                    },
                    "negative_domain_keywords": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Negative domain keywords separated by newlines. Domains containing these keywords will be excluded from monitoring."
                    },
                    "brand_keywords": {
                        "type": "string",
                        "nullable": true,
                        "description": "Brand keywords separated by newlines. These keywords are associated with the brand for monitoring purposes. The brand name is always included automatically."
                    },
                    "monitoring_enabled": {
                        "type": "boolean",
                        "readOnly": true,
                        "description": "Product-level switch and source of truth for tab-locking and the inert-brand scan/AI gates. Defaults True so every normal creation path keeps producing fully-monitored brands. Only the takedown-only onboarding flow sets this False (an inert brand has both this and continuous_scanning / continuous_visual_scan False)."
                    },
                    "origin": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/OriginEnum"
                            }
                        ],
                        "readOnly": true,
                        "description": "Provenance for conversion-funnel analytics. Not the gate for tab-locking (that is monitoring_enabled) — this is the positive segmentation marker.\n\n* `self_signup` - Self Signup\n* `staff_onboarding_takedown` - Staff Onboarding (Takedown)\n* `staff_onboarding_monitoring` - Staff Onboarding (Monitoring)\n* `sales` - Sales\n* `partner` - Partner"
                    },
                    "executives": {
                        "type": "string",
                        "nullable": true,
                        "description": "Executive names separated by newlines. Used for LinkedIn social media scanning and included in brand keywords."
                    },
                    "trusted_social_media_profiles": {
                        "description": "List of trusted social media profiles, e.g. [{\"channel\": \"instagram\", \"username\": \"acmecorp\"}]."
                    },
                    "dismissed_social_media_profiles": {
                        "description": "List of dismissed social media profiles, e.g. [{\"channel\": \"instagram\", \"username\": \"spammer123\"}]."
                    },
                    "trusted_meta_page_ids": {
                        "description": "List of trusted Meta page IDs (Facebook/Instagram pages) that should be skipped during Meta Ad Library relevance scoring, e.g. [\"123456789\"]. Useful for the brand's own pages and known legitimate partners."
                    },
                    "dismissed_meta_page_ids": {
                        "description": "List of dismissed Meta page IDs that should be skipped during Meta Ad Library relevance scoring, e.g. [\"987654321\"]."
                    },
                    "dismissed_meta_ad_ids": {
                        "description": "List of dismissed Meta ad IDs (the ad.id from the Meta Ad Library), e.g. [\"123456789012345\"]. Ads in this list are hidden from the user's view by default and skipped during AI relevance scoring. User-controlled per-ad dismiss."
                    },
                    "company_name": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Official company/legal entity name (e.g. 'Cashlink Technologies GmbH'). AI-generated via OpenAI web search. Editable in admin for manual override."
                    },
                    "brand_markets": {
                        "readOnly": true,
                        "description": "ISO 3166-1 alpha-2 country codes for the brand's main markets, e.g. ['US', 'DE']. AI-generated."
                    },
                    "triage_enabled": {
                        "type": "boolean",
                        "description": "Per-brand switch for common-word triage. Off by default so a generated profile cannot act on a brand until it has been reviewed by hand (§5)."
                    },
                    "linkedin_company_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "LinkedIn company page URL, e.g. https://www.linkedin.com/company/coinroutes/",
                        "maxLength": 200
                    }
                },
                "required": [
                    "all_keywords",
                    "brand_markets",
                    "company_name",
                    "created_at",
                    "domain",
                    "has_own_website",
                    "id",
                    "monitoring_enabled",
                    "my_role",
                    "name",
                    "negative_domain_keywords",
                    "negative_variations",
                    "origin",
                    "plan",
                    "seat_limit",
                    "seats_used",
                    "trusted_domains",
                    "updated_at"
                ]
            },
            "BrandDomainApexGroup": {
                "type": "object",
                "description": "One row of the apex-grouped brand domain list (``?group_by=apex``).\n\nNot a ModelSerializer: a row is an aggregate over many Domains, not one of\nthem. ``registrable_apex`` falls back to the hostname for rows whose apex\ncolumn is unset, so every domain is represented in exactly one group and\nthe ``domain_count`` values sum to the ungrouped row count.",
                "properties": {
                    "registrable_apex": {
                        "type": "string",
                        "description": "Registrable apex (eTLD+1) shared by every host in this group."
                    },
                    "domain_count": {
                        "type": "integer",
                        "description": "How many hostnames in this brand's list share this apex."
                    },
                    "max_risk_score": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Highest pair risk score among the group's hosts. The worst host decides the group, so collapsing rows can never lower a score."
                    }
                },
                "required": [
                    "domain_count",
                    "max_risk_score",
                    "registrable_apex"
                ]
            },
            "BrandDomainListItem": {
                "anyOf": [
                    {
                        "$ref": "#/components/schemas/Domain"
                    },
                    {
                        "$ref": "#/components/schemas/CompactDomain"
                    },
                    {
                        "$ref": "#/components/schemas/BrandDomainApexGroup"
                    }
                ]
            },
            "BrandListItem": {
                "anyOf": [
                    {
                        "$ref": "#/components/schemas/Brand"
                    },
                    {
                        "$ref": "#/components/schemas/BrandWithStats"
                    },
                    {
                        "$ref": "#/components/schemas/CompactBrand"
                    }
                ]
            },
            "BrandScanListItem": {
                "anyOf": [
                    {
                        "$ref": "#/components/schemas/DomainScan"
                    },
                    {
                        "$ref": "#/components/schemas/CompactDomainScan"
                    }
                ]
            },
            "BrandStats": {
                "type": "object",
                "description": "Serializer for comprehensive brand statistics.",
                "properties": {
                    "domain_risk_distribution": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "description": "Domain-based buckets summing to domain_count, including zero risk and unscanned. Prefer these over legacy risk_distribution, which counts scan rows at scores 1+."
                    },
                    "domain_count": {
                        "type": "integer"
                    },
                    "domain_review_count": {
                        "type": "integer",
                        "description": "High-risk domains (pair score 8+) a person still has to decide on: not trusted and not marked 'Not relevant'. Same population as domain_risk_distribution, whose buckets still count marked domains."
                    },
                    "scan_count": {
                        "type": "integer"
                    },
                    "latest_scan_date": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "high_risk_count": {
                        "type": "integer"
                    },
                    "average_risk_score": {
                        "type": "number",
                        "format": "double"
                    },
                    "risk_distribution": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "description": "Risk distribution with low_risk_count, medium_risk_count, high_risk_count"
                    },
                    "visual_match_stats": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "description": "Deprecated — use verdict_stats. Visual match statistics with visual_matches_found, no_visual_matches, unknown_visual_matches"
                    },
                    "verdict_stats": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "description": "Verdict statistics with red, amber, green, unknown counts. Matches the values accepted by the domains list endpoint's verdict_filter query parameter."
                    },
                    "http_status_stats": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "description": "HTTP status statistics with live_domains, error_domains, unknown_status"
                    }
                },
                "required": [
                    "average_risk_score",
                    "domain_count",
                    "domain_review_count",
                    "high_risk_count",
                    "http_status_stats",
                    "latest_scan_date",
                    "risk_distribution",
                    "scan_count",
                    "verdict_stats",
                    "visual_match_stats"
                ]
            },
            "BrandWithStats": {
                "type": "object",
                "description": "Serializer for brand with included comprehensive statistics.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "domain": {
                        "type": "string",
                        "description": "The domain of the brand.",
                        "maxLength": 255
                    },
                    "domain_count": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "scan_count": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "latest_scan_date": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "readOnly": true
                    },
                    "high_risk_count": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "average_risk_score": {
                        "type": "number",
                        "format": "double",
                        "readOnly": true
                    },
                    "risk_distribution": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "readOnly": true
                    },
                    "visual_match_stats": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "readOnly": true
                    },
                    "verdict_stats": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "readOnly": true
                    },
                    "http_status_stats": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "integer"
                        },
                        "readOnly": true
                    },
                    "trusted_domains": {
                        "type": "array",
                        "items": {},
                        "description": "Return trusted domain names, using prefetch cache when available.",
                        "readOnly": true
                    },
                    "seat_limit": {
                        "type": "integer",
                        "nullable": true,
                        "readOnly": true
                    },
                    "seats_used": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "my_role": {
                        "type": "string",
                        "nullable": true,
                        "readOnly": true
                    },
                    "negative_keywords": {
                        "type": "string",
                        "nullable": true,
                        "description": "Newline-separated terms to exclude from generated variations and domain matches for this brand. Replaces negative_variations and negative_domain_keywords, which are now read-only."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "name": {
                        "type": "string",
                        "description": "The name of the brand, e.g. 'Cashlink'.",
                        "maxLength": 255
                    },
                    "has_own_website": {
                        "type": "boolean",
                        "readOnly": true,
                        "description": "Whether the customer has a website of their own. When False, `domain` holds a derived .invalid sentinel that anchors similarity scoring but is NOT treated as an identity term."
                    },
                    "plan": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/PlanEnum"
                            }
                        ],
                        "readOnly": true,
                        "description": "Per-brand subscription tier. Determines seat limit and write capability for members without a multi-brand AccountType. See docs/subscription-plans.md.\n\n* `free` - Free\n* `basic` - Basic\n* `business` - Business\n* `unlimited` - Unlimited"
                    },
                    "last_variation_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When was the last variation of the domain generated?"
                    },
                    "negative_variations": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Negative keywords separated by newlines. Variations containing these keywords will be removed."
                    },
                    "negative_domain_keywords": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Negative domain keywords separated by newlines. Domains containing these keywords will be excluded from monitoring."
                    },
                    "brand_keywords": {
                        "type": "string",
                        "nullable": true,
                        "description": "Brand keywords separated by newlines. These keywords are associated with the brand for monitoring purposes. The brand name is always included automatically."
                    },
                    "monitoring_enabled": {
                        "type": "boolean",
                        "readOnly": true,
                        "description": "Product-level switch and source of truth for tab-locking and the inert-brand scan/AI gates. Defaults True so every normal creation path keeps producing fully-monitored brands. Only the takedown-only onboarding flow sets this False (an inert brand has both this and continuous_scanning / continuous_visual_scan False)."
                    },
                    "origin": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/OriginEnum"
                            }
                        ],
                        "readOnly": true,
                        "description": "Provenance for conversion-funnel analytics. Not the gate for tab-locking (that is monitoring_enabled) — this is the positive segmentation marker.\n\n* `self_signup` - Self Signup\n* `staff_onboarding_takedown` - Staff Onboarding (Takedown)\n* `staff_onboarding_monitoring` - Staff Onboarding (Monitoring)\n* `sales` - Sales\n* `partner` - Partner"
                    },
                    "executives": {
                        "type": "string",
                        "nullable": true,
                        "description": "Executive names separated by newlines. Used for LinkedIn social media scanning and included in brand keywords."
                    },
                    "trusted_social_media_profiles": {
                        "description": "List of trusted social media profiles, e.g. [{\"channel\": \"instagram\", \"username\": \"acmecorp\"}]."
                    },
                    "dismissed_social_media_profiles": {
                        "description": "List of dismissed social media profiles, e.g. [{\"channel\": \"instagram\", \"username\": \"spammer123\"}]."
                    },
                    "trusted_meta_page_ids": {
                        "description": "List of trusted Meta page IDs (Facebook/Instagram pages) that should be skipped during Meta Ad Library relevance scoring, e.g. [\"123456789\"]. Useful for the brand's own pages and known legitimate partners."
                    },
                    "dismissed_meta_page_ids": {
                        "description": "List of dismissed Meta page IDs that should be skipped during Meta Ad Library relevance scoring, e.g. [\"987654321\"]."
                    },
                    "dismissed_meta_ad_ids": {
                        "description": "List of dismissed Meta ad IDs (the ad.id from the Meta Ad Library), e.g. [\"123456789012345\"]. Ads in this list are hidden from the user's view by default and skipped during AI relevance scoring. User-controlled per-ad dismiss."
                    },
                    "company_name": {
                        "type": "string",
                        "nullable": true,
                        "description": "Official company/legal entity name (e.g. 'Cashlink Technologies GmbH'). AI-generated via OpenAI web search. Editable in admin for manual override."
                    },
                    "brand_markets": {
                        "description": "ISO 3166-1 alpha-2 country codes for the brand's main markets, e.g. ['US', 'DE']. AI-generated."
                    },
                    "triage_enabled": {
                        "type": "boolean",
                        "description": "Per-brand switch for common-word triage. Off by default so a generated profile cannot act on a brand until it has been reviewed by hand (§5)."
                    },
                    "linkedin_company_url": {
                        "type": "string",
                        "format": "uri",
                        "description": "LinkedIn company page URL, e.g. https://www.linkedin.com/company/coinroutes/",
                        "maxLength": 200
                    }
                },
                "required": [
                    "average_risk_score",
                    "created_at",
                    "domain",
                    "domain_count",
                    "has_own_website",
                    "high_risk_count",
                    "http_status_stats",
                    "id",
                    "latest_scan_date",
                    "monitoring_enabled",
                    "my_role",
                    "name",
                    "negative_domain_keywords",
                    "negative_variations",
                    "origin",
                    "plan",
                    "risk_distribution",
                    "scan_count",
                    "seat_limit",
                    "seats_used",
                    "trusted_domains",
                    "updated_at",
                    "verdict_stats",
                    "visual_match_stats"
                ]
            },
            "ClosedAtSourceEnum": {
                "enum": [
                    "MEASURED",
                    "DERIVED_FROM_EVENT",
                    "DERIVED_FROM_NOTE"
                ],
                "type": "string",
                "description": "* `MEASURED` - Measured at closure\n* `DERIVED_FROM_EVENT` - Derived from status-change event\n* `DERIVED_FROM_NOTE` - Derived from last case note (±1 day)"
            },
            "CompactBrand": {
                "type": "object",
                "description": "Brand discovery without keywords, billing identifiers or internal data.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "name": {
                        "type": "string",
                        "readOnly": true,
                        "description": "The name of the brand, e.g. 'Cashlink'."
                    },
                    "domain": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true,
                        "description": "The domain of the brand, e.g. 'cashlink.de'."
                    },
                    "plan": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/PlanEnum"
                            }
                        ],
                        "readOnly": true,
                        "description": "Per-brand subscription tier. Determines seat limit and write capability for members without a multi-brand AccountType. See docs/subscription-plans.md.\n\n* `free` - Free\n* `basic` - Basic\n* `business` - Business\n* `unlimited` - Unlimited"
                    },
                    "monitoring_enabled": {
                        "type": "boolean",
                        "readOnly": true,
                        "description": "Product-level switch and source of truth for tab-locking and the inert-brand scan/AI gates. Defaults True so every normal creation path keeps producing fully-monitored brands. Only the takedown-only onboarding flow sets this False (an inert brand has both this and continuous_scanning / continuous_visual_scan False)."
                    },
                    "brand_markets": {
                        "readOnly": true,
                        "description": "ISO 3166-1 alpha-2 country codes for the brand's main markets, e.g. ['US', 'DE']. AI-generated."
                    }
                },
                "required": [
                    "brand_markets",
                    "domain",
                    "id",
                    "monitoring_enabled",
                    "name",
                    "plan"
                ]
            },
            "CompactDomain": {
                "type": "object",
                "description": "Serializer for Domain model.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "source": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/DomainSourceEnum"
                            }
                        ],
                        "description": "How this domain was discovered/added to the system\n\n* `VARIATION` - Generated from Variation\n* `CERTSTREAM` - CertStream API\n* `SUBDOMAIN_SCAN` - Subdomain Scan\n* `MANUAL` - Manual Entry\n* `AD_LIBRARY` - Meta Ad Library\n* `CONTENT_SEARCH` - Content search (page title)\n* `PATTERN_HUNT` - Pattern search"
                    },
                    "latest_scan": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/CompactDomainScan"
                            }
                        ],
                        "readOnly": true
                    },
                    "open_takedown": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/OpenTakedown"
                            }
                        ],
                        "nullable": true,
                        "readOnly": true
                    },
                    "last_closed_takedown": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/LastClosedTakedown"
                            }
                        ],
                        "nullable": true,
                        "readOnly": true
                    },
                    "takedown": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/FindingTakedown"
                            }
                        ],
                        "nullable": true,
                        "readOnly": true
                    },
                    "dismissed_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When this brand marked the domain 'Not relevant' (POST .../set-dismissed/). Null when not marked. The mark never changes the risk score.",
                        "readOnly": true
                    },
                    "dismissed_by": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "User who marked the domain 'Not relevant'. Null when not marked, or when that account was deleted.",
                        "readOnly": true
                    }
                },
                "required": [
                    "dismissed_at",
                    "dismissed_by",
                    "id",
                    "last_closed_takedown",
                    "latest_scan",
                    "name",
                    "open_takedown",
                    "takedown"
                ]
            },
            "CompactDomainScan": {
                "type": "object",
                "description": "Bounded scan summary; evidence and history live in domain detail.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "domain": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "domain_name": {
                        "type": "string",
                        "readOnly": true
                    },
                    "risk_score": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "verdict": {
                        "type": "string",
                        "description": "The single customer-facing verdict, resolved for the requesting brand.\n\nUnlike ``risk_score``/``visual_match`` there is no shared ``DomainScan``\ncolumn to fall back to: the merged verdict has only ever lived on the\npair (``BrandDomainAssociation.refresh_merged_verdict``), so a caller\nwith no brand in context — or a historical scan row, which carries no\npair-specific verdict of its own — gets \"unknown\" rather than another\nbrand's answer.",
                        "readOnly": true
                    },
                    "requires_human_review": {
                        "type": "boolean",
                        "readOnly": true
                    },
                    "https_head_request_response_code": {
                        "type": "integer",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "created_at",
                    "domain",
                    "domain_name",
                    "id",
                    "requires_human_review",
                    "risk_score",
                    "updated_at",
                    "verdict"
                ]
            },
            "Domain": {
                "type": "object",
                "description": "Serializer for Domain model.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "source": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/DomainSourceEnum"
                            }
                        ],
                        "description": "How this domain was discovered/added to the system\n\n* `VARIATION` - Generated from Variation\n* `CERTSTREAM` - CertStream API\n* `SUBDOMAIN_SCAN` - Subdomain Scan\n* `MANUAL` - Manual Entry\n* `AD_LIBRARY` - Meta Ad Library\n* `CONTENT_SEARCH` - Content search (page title)\n* `PATTERN_HUNT` - Pattern search"
                    },
                    "parent": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true
                    },
                    "associated_brands": {
                        "type": "array",
                        "items": {
                            "type": "string",
                            "format": "uuid"
                        },
                        "readOnly": true
                    },
                    "latest_scan": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/DomainScan"
                            }
                        ],
                        "readOnly": true
                    },
                    "scans": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/DomainScan"
                        },
                        "readOnly": true
                    },
                    "open_takedown": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/OpenTakedown"
                            }
                        ],
                        "nullable": true,
                        "readOnly": true
                    },
                    "last_closed_takedown": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/LastClosedTakedown"
                            }
                        ],
                        "nullable": true,
                        "readOnly": true
                    },
                    "takedown": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/FindingTakedown"
                            }
                        ],
                        "nullable": true,
                        "readOnly": true
                    },
                    "dismissed_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When this brand marked the domain 'Not relevant' (POST .../set-dismissed/). Null when not marked. The mark never changes the risk score.",
                        "readOnly": true
                    },
                    "dismissed_by": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "User who marked the domain 'Not relevant'. Null when not marked, or when that account was deleted.",
                        "readOnly": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "associated_brands",
                    "created_at",
                    "dismissed_at",
                    "dismissed_by",
                    "id",
                    "last_closed_takedown",
                    "latest_scan",
                    "name",
                    "open_takedown",
                    "scans",
                    "takedown",
                    "updated_at"
                ]
            },
            "DomainScan": {
                "type": "object",
                "description": "Serializer for DomainScan model.\n\n``risk_score`` and ``visual_match`` are answers about a brand↔domain *pair*,\nnot about the domain (#954). When the caller puts a ``brand`` in the\nserializer context — every brand-scoped endpoint does — both are rendered\nfrom that brand's association, so a domain two customers monitor shows each\nof them the verdict computed against their own brand.\n\nWithout a brand in context the shared columns are rendered unchanged, which\nis what the domain-global endpoints and the admin want. That column now\nmeans \"the worst score across every brand monitoring this domain\" rather\nthan \"the longest-monitored brand's score\" — see\n``DomainScan.get_risk_score``.\n\n``verdict``/``verdict_reasoning``/``requires_human_review`` are the single\ncustomer-facing verdict merged from the visual and content detectors\n(``BrandDomainAssociation.refresh_merged_verdict``) and are what the\nfrontend should read going forward. ``visual_match`` is kept in the payload\nas **deprecated** — do not remove it — because it still governs code paths\nmid-migration; new consumers should read ``verdict`` instead.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "domain": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "mx_records": {
                        "type": "string",
                        "nullable": true
                    },
                    "a_records": {
                        "type": "string",
                        "nullable": true
                    },
                    "cname_records": {
                        "type": "string",
                        "nullable": true
                    },
                    "visual_match": {
                        "type": "boolean",
                        "nullable": true,
                        "readOnly": true
                    },
                    "verdict": {
                        "type": "string",
                        "description": "The single customer-facing verdict, resolved for the requesting brand.\n\nUnlike ``risk_score``/``visual_match`` there is no shared ``DomainScan``\ncolumn to fall back to: the merged verdict has only ever lived on the\npair (``BrandDomainAssociation.refresh_merged_verdict``), so a caller\nwith no brand in context — or a historical scan row, which carries no\npair-specific verdict of its own — gets \"unknown\" rather than another\nbrand's answer.",
                        "readOnly": true
                    },
                    "verdict_reasoning": {
                        "type": "string",
                        "nullable": true,
                        "readOnly": true
                    },
                    "requires_human_review": {
                        "type": "boolean",
                        "readOnly": true
                    },
                    "visual_scan_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When *this brand* last had the domain visually scanned.\n\nThe shared timestamp is whichever brand scanned the domain most\nrecently, so on a shared hostname it is somebody else's. NULL on the\npair means this brand has not scanned it yet, which is exactly what the\ncooldown treats it as.",
                        "readOnly": true
                    },
                    "screenshot_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "description": "URL to the screenshot of the domain stored in Hetzner S3-compatible Object Storage",
                        "maxLength": 2000
                    },
                    "https_head_request_response_code": {
                        "type": "integer",
                        "nullable": true
                    },
                    "unreachable_since": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When the current run of scans with no HTTP answer at all (https_head_request_response_code 600) began. Null while the latest scan got any HTTP status, 4xx included.",
                        "readOnly": true
                    },
                    "certificate": {
                        "type": "string",
                        "nullable": true
                    },
                    "scans_executed": {
                        "type": "integer"
                    },
                    "is_alerting_event": {
                        "type": "boolean",
                        "nullable": true,
                        "description": "Whether *this brand* still has an unsent alert for the domain.\n\nThe shared flag means \"somebody has one\", so after this brand's alert\nwas sent it would keep reporting true while another brand's is pending.",
                        "readOnly": true
                    },
                    "completeness": {
                        "type": "integer",
                        "readOnly": true,
                        "description": "A completeness of 0 means that the domain has no records set. The higher this number, the more likely the domain is actually used."
                    },
                    "risk_score": {
                        "type": "integer",
                        "readOnly": true
                    },
                    "scan_history": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "additionalProperties": {}
                        },
                        "description": "The domain's scan timeline, most recent first.\n\nOn a domain that has only ever had single-brand history, the whole\nhistory is this brand's own and renders untouched. Once branded rows\nexist, the domain has had a multi-brand period: the requesting brand then\nsees only its own rows, and NULL-brand rows are redacted because current\nassociation count can no longer prove which brand they belonged to.",
                        "readOnly": true
                    },
                    "user_feedback_type": {
                        "nullable": true,
                        "description": "User feedback: false_positive overrides risk to 0, comment is informational. Resolved for the requesting brand.\n\n* `false_positive` - False Positive\n* `comment` - Comment",
                        "readOnly": true,
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/FeedbackTypeEnum"
                            },
                            {
                                "$ref": "#/components/schemas/NullEnum"
                            }
                        ]
                    },
                    "user_feedback_comment": {
                        "type": "string",
                        "description": "Free text comment from the user.",
                        "readOnly": true
                    },
                    "user_feedback_by": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "User who submitted the feedback.",
                        "readOnly": true
                    },
                    "user_feedback_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When the feedback was submitted.",
                        "readOnly": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "completeness",
                    "created_at",
                    "domain",
                    "id",
                    "is_alerting_event",
                    "requires_human_review",
                    "risk_score",
                    "scan_history",
                    "unreachable_since",
                    "updated_at",
                    "user_feedback_at",
                    "user_feedback_by",
                    "user_feedback_comment",
                    "user_feedback_type",
                    "verdict",
                    "verdict_reasoning",
                    "visual_match",
                    "visual_scan_at"
                ]
            },
            "DomainSourceEnum": {
                "enum": [
                    "VARIATION",
                    "CERTSTREAM",
                    "SUBDOMAIN_SCAN",
                    "MANUAL",
                    "AD_LIBRARY",
                    "CONTENT_SEARCH",
                    "PATTERN_HUNT"
                ],
                "type": "string",
                "description": "* `VARIATION` - Generated from Variation\n* `CERTSTREAM` - CertStream API\n* `SUBDOMAIN_SCAN` - Subdomain Scan\n* `MANUAL` - Manual Entry\n* `AD_LIBRARY` - Meta Ad Library\n* `CONTENT_SEARCH` - Content search (page title)\n* `PATTERN_HUNT` - Pattern search"
            },
            "FeedbackTypeEnum": {
                "enum": [
                    "false_positive",
                    "comment"
                ],
                "type": "string",
                "description": "* `false_positive` - False Positive\n* `comment` - Comment"
            },
            "FindingTakedown": {
                "type": "object",
                "description": "The takedown that covers a finding (B2): any status except REJECTED.\n\nUnlike ``open_takedown`` / ``last_closed_takedown`` this answers \"has the\ncustomer acted on this finding\", so REQUESTED, CLOSED and FAILED all show.\nA finding with a takedown is left out of the attention counts.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Takedown id; fetch the case at GET /core/api/takedowns/{id}/."
                    },
                    "status": {
                        "type": "string",
                        "description": "Raw Takedown.status value, e.g. REQUESTED, OPEN, CLOSED."
                    }
                },
                "required": [
                    "id",
                    "status"
                ]
            },
            "LastClosedTakedown": {
                "type": "object",
                "description": "The requesting brand's newest FINISHED takedown case for a hostname.\n\nLean on purpose, like ``OpenTakedownSerializer``: enough to draw a\n\"Takedown: <result>\" badge and link to the case. The full case lives at\n``/core/api/takedowns/{id}/``.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Takedown id; fetch the case at GET /core/api/takedowns/{id}/."
                    },
                    "status": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/LastClosedTakedownStatusEnum"
                            }
                        ],
                        "description": "How the case ended: CLOSED (worked to a conclusion, see `resolution`) or FAILED (abandoned, no resolution).\n\n* `CLOSED` - Closed\n* `FAILED` - Failed"
                    },
                    "resolution": {
                        "nullable": true,
                        "description": "Outcome of a CLOSED case. FALSE_POSITIVE means the analysts found no infringement. Null for FAILED, and for a CLOSED case that was closed without a resolution.\n\n* `DOMAIN_SUSPENDED` - Domain Suspended\n* `CONTENT_REMOVED` - Content Removed\n* `SERVER_HOLD` - Server Hold\n* `VOLUNTARY_TAKEDOWN` - Voluntary Takedown\n* `UNRESOLVED` - Unresolved\n* `FALSE_POSITIVE` - False Positive\n* `TOKEN_LISTING_REMOVED` - Agreed token listing removed\n* `TOKEN_TRADING_BLOCKED` - Trading blocked on agreed platform\n* `TOKEN_WARNING_ADDED` - Token warning added (partial mitigation)",
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/TakedownResolutionEnum"
                            },
                            {
                                "$ref": "#/components/schemas/NullEnum"
                            }
                        ]
                    },
                    "closed_at": {
                        "type": "string",
                        "format": "date-time",
                        "description": "When the case finished. For CLOSED this is the case's `closed_at`; FAILED and undated legacy cases use a stable result timestamp."
                    }
                },
                "required": [
                    "closed_at",
                    "id",
                    "resolution",
                    "status"
                ]
            },
            "LastClosedTakedownStatusEnum": {
                "enum": [
                    "CLOSED",
                    "FAILED"
                ],
                "type": "string",
                "description": "* `CLOSED` - Closed\n* `FAILED` - Failed"
            },
            "NullEnum": {
                "enum": [
                    null
                ]
            },
            "OpenTakedown": {
                "type": "object",
                "description": "The requesting brand's running takedown case for a hostname.\n\nLean on purpose: id and status only. The full case lives at\n``/core/api/takedowns/{id}/`` and a second payload of it here would be a\ncontract to keep in sync for a badge.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "description": "Takedown id; fetch the case at GET /core/api/takedowns/{id}/."
                    },
                    "status": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/TakedownStatusEnum"
                            }
                        ],
                        "description": "Current status of the running case.\n\n* `REQUESTED` - Pending review\n* `OPEN` - Open\n* `IN_PROGRESS` - In Progress\n* `PENDING_RESPONSE` - Pending Response\n* `CLOSED` - Closed\n* `FAILED` - Failed\n* `REJECTED` - Rejected"
                    }
                },
                "required": [
                    "id",
                    "status"
                ]
            },
            "OriginEnum": {
                "enum": [
                    "self_signup",
                    "staff_onboarding_takedown",
                    "staff_onboarding_monitoring",
                    "sales",
                    "partner"
                ],
                "type": "string",
                "description": "* `self_signup` - Self Signup\n* `staff_onboarding_takedown` - Staff Onboarding (Takedown)\n* `staff_onboarding_monitoring` - Staff Onboarding (Monitoring)\n* `sales` - Sales\n* `partner` - Partner"
            },
            "PaginatedBrandListItemList": {
                "type": "object",
                "required": [
                    "count",
                    "results"
                ],
                "properties": {
                    "count": {
                        "type": "integer",
                        "example": 123
                    },
                    "next": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=4"
                    },
                    "previous": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=2"
                    },
                    "results": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/BrandListItem"
                        }
                    }
                }
            },
            "PaginatedBrandScanListItemList": {
                "type": "object",
                "required": [
                    "count",
                    "results"
                ],
                "properties": {
                    "count": {
                        "type": "integer",
                        "example": 123
                    },
                    "next": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=4"
                    },
                    "previous": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=2"
                    },
                    "results": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/BrandScanListItem"
                        }
                    }
                }
            },
            "PaginatedTakedownEventList": {
                "type": "object",
                "required": [
                    "count",
                    "results"
                ],
                "properties": {
                    "count": {
                        "type": "integer",
                        "example": 123
                    },
                    "next": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=4"
                    },
                    "previous": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=2"
                    },
                    "results": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/TakedownEvent"
                        }
                    }
                }
            },
            "PaginatedTakedownList": {
                "type": "object",
                "required": [
                    "count",
                    "results"
                ],
                "properties": {
                    "count": {
                        "type": "integer",
                        "example": 123
                    },
                    "next": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=4"
                    },
                    "previous": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=2"
                    },
                    "results": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Takedown"
                        }
                    }
                }
            },
            "PlanEnum": {
                "enum": [
                    "free",
                    "basic",
                    "business",
                    "unlimited"
                ],
                "type": "string",
                "description": "* `free` - Free\n* `basic` - Basic\n* `business` - Business\n* `unlimited` - Unlimited"
            },
            "SubscriptionCurrencyEnum": {
                "enum": [
                    "USD",
                    "CAD",
                    "EUR"
                ],
                "type": "string",
                "description": "* `USD` - US$\n* `CAD` - CA$\n* `EUR` - EUR"
            },
            "Takedown": {
                "type": "object",
                "description": "Serializer for takedown request details.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "target_website": {
                        "type": "string",
                        "format": "uri",
                        "description": "The target website URL for the takedown request",
                        "maxLength": 500
                    },
                    "category": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/TakedownCategoryEnum"
                            }
                        ],
                        "description": "What the case is against. 'token' is a fake crypto token (smart contract); target_website then holds the contract's block-explorer URL, and the domain autofill and post-close rescan skip the row. Only staff may set 'token'.\n\n* `website` - Website\n* `token` - Token"
                    },
                    "token_platform": {
                        "type": "string",
                        "format": "uri",
                        "description": "Token only: the specific listing or trading platform covered by the customer's order.",
                        "maxLength": 500
                    },
                    "token_objective": {
                        "description": "Token only: the removal or trading block agreed before work starts.\n\n* `listing_removed` - Remove the agreed token listing\n* `trading_blocked` - Block trading on the agreed platform",
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/TokenTakedownObjectiveEnum"
                            },
                            {
                                "$ref": "#/components/schemas/BlankEnum"
                            }
                        ]
                    },
                    "token_agreed_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Server timestamp when the complete token order scope was first recorded. The scope is then immutable."
                    },
                    "requesting_user_email": {
                        "type": "string",
                        "readOnly": true
                    },
                    "user_comment": {
                        "type": "string",
                        "nullable": true,
                        "description": "Optional comment from the requesting user"
                    },
                    "brand": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Brand associated with this takedown. All users with access to this brand can view the takedown."
                    },
                    "brand_display": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true
                    },
                    "brand_name": {
                        "type": "string",
                        "nullable": true,
                        "description": "Legacy free-text brand name (deprecated, use brand FK instead)",
                        "maxLength": 255
                    },
                    "status": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/TakedownStatusEnum"
                            }
                        ],
                        "readOnly": true,
                        "description": "Current status of the takedown request\n\n* `REQUESTED` - Pending review\n* `OPEN` - Open\n* `IN_PROGRESS` - In Progress\n* `PENDING_RESPONSE` - Pending Response\n* `CLOSED` - Closed\n* `FAILED` - Failed\n* `REJECTED` - Rejected"
                    },
                    "status_display": {
                        "type": "string",
                        "readOnly": true
                    },
                    "is_open": {
                        "type": "boolean",
                        "readOnly": true
                    },
                    "closed_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Timestamp when the takedown case was closed."
                    },
                    "closed_at_source": {
                        "readOnly": true,
                        "description": "How closed_at was arrived at: MEASURED (stamped at closure or entered by staff), DERIVED_FROM_EVENT (reconstructed from the status-change audit event, exact), DERIVED_FROM_NOTE (reconstructed from the last case note, +/-1 day), or blank when no closing date is known. Reports averaging resolution time should state how many inputs were reconstructed.\n\n* `MEASURED` - Measured at closure\n* `DERIVED_FROM_EVENT` - Derived from status-change event\n* `DERIVED_FROM_NOTE` - Derived from last case note (±1 day)",
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/ClosedAtSourceEnum"
                            },
                            {
                                "$ref": "#/components/schemas/BlankEnum"
                            }
                        ]
                    },
                    "resolution": {
                        "readOnly": true,
                        "nullable": true,
                        "description": "Outcome of the takedown case.\n\n* `DOMAIN_SUSPENDED` - Domain Suspended\n* `CONTENT_REMOVED` - Content Removed\n* `SERVER_HOLD` - Server Hold\n* `VOLUNTARY_TAKEDOWN` - Voluntary Takedown\n* `UNRESOLVED` - Unresolved\n* `FALSE_POSITIVE` - False Positive\n* `TOKEN_LISTING_REMOVED` - Agreed token listing removed\n* `TOKEN_TRADING_BLOCKED` - Trading blocked on agreed platform\n* `TOKEN_WARNING_ADDED` - Token warning added (partial mitigation)",
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/TakedownResolutionEnum"
                            },
                            {
                                "$ref": "#/components/schemas/NullEnum"
                            }
                        ]
                    },
                    "resolution_display": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true
                    },
                    "price": {
                        "type": "string",
                        "format": "decimal",
                        "pattern": "^-?\\d{0,8}(?:\\.\\d{0,2})?$",
                        "readOnly": true,
                        "nullable": true,
                        "description": "Price per successful takedown, net plus VAT, that the customer accepted with the order. 0.00 is a real price; null means no price was frozen."
                    },
                    "price_currency": {
                        "readOnly": true,
                        "description": "Currency of `price`; blank when no price was accepted with the order.\n\n* `USD` - US$\n* `CAD` - CA$\n* `EUR` - EUR",
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/SubscriptionCurrencyEnum"
                            },
                            {
                                "$ref": "#/components/schemas/BlankEnum"
                            }
                        ]
                    },
                    "registrar": {
                        "type": "string",
                        "nullable": true,
                        "description": "Domain registrar, e.g. 'Openprovider', 'Sav.com'",
                        "maxLength": 255
                    },
                    "domain_created_at": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Domain registration date from WHOIS."
                    },
                    "domain_expires_at": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Domain expiry date from WHOIS."
                    },
                    "domain_status": {
                        "type": "string",
                        "nullable": true,
                        "description": "WHOIS status, e.g. 'clientTransferProhibited', 'serverHold'",
                        "maxLength": 255
                    },
                    "ip_address": {
                        "type": "string",
                        "nullable": true,
                        "description": "Resolved IP address (may be proxy IP)."
                    },
                    "origin_ip": {
                        "type": "string",
                        "nullable": true,
                        "description": "Real server IP behind CDN/proxy."
                    },
                    "asn": {
                        "type": "string",
                        "nullable": true,
                        "description": "AS number, e.g. 'AS13335'",
                        "maxLength": 20
                    },
                    "hosting_provider": {
                        "type": "string",
                        "nullable": true,
                        "description": "Hosting provider, e.g. 'Hostinger', 'Hetzner'",
                        "maxLength": 255
                    },
                    "cdn_proxy": {
                        "type": "string",
                        "nullable": true,
                        "description": "CDN/proxy provider, e.g. 'Cloudflare'",
                        "maxLength": 255
                    },
                    "is_proxied": {
                        "type": "boolean",
                        "description": "Whether the domain is behind a CDN/proxy."
                    },
                    "backend_provider": {
                        "type": "string",
                        "nullable": true,
                        "description": "Backend service, e.g. 'Supabase', 'Vercel'",
                        "maxLength": 255
                    },
                    "backend_project_id": {
                        "type": "string",
                        "nullable": true,
                        "description": "Project ID at backend provider.",
                        "maxLength": 255
                    },
                    "ssl_issued_at": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "SSL certificate issue date."
                    },
                    "ssl_expires_at": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "SSL certificate expiry date."
                    },
                    "ssl_issuer": {
                        "type": "string",
                        "nullable": true,
                        "description": "Certificate issuer, e.g. 'Let's Encrypt', 'Cloudflare'",
                        "maxLength": 255
                    },
                    "a_entry": {
                        "type": "string",
                        "nullable": true,
                        "description": "DNS A record information (DEPRECATED - use dns_raw)"
                    },
                    "ns_entry": {
                        "type": "string",
                        "nullable": true,
                        "description": "DNS NS record information (DEPRECATED - use dns_raw)"
                    },
                    "dns_raw": {
                        "nullable": true,
                        "description": "Full DNS records as JSON. Expected structure: {\"a\": [...], \"aaaa\": [...], \"cname\": [...], \"mx\": [...], \"ns\": [...], \"txt\": [...], \"soa\": [...], \"caa\": [...]}"
                    },
                    "virustotal_score": {
                        "type": "string",
                        "nullable": true,
                        "description": "Score, e.g. '16/93'",
                        "maxLength": 20
                    },
                    "virustotal_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "description": "Link to VirusTotal report.",
                        "maxLength": 200
                    },
                    "urlscan_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "description": "Link to urlscan.io result.",
                        "maxLength": 200
                    },
                    "screenshot_url": {
                        "type": "string",
                        "format": "uri",
                        "nullable": true,
                        "description": "URL to screenshot in Hetzner S3 Object Storage.",
                        "maxLength": 2000
                    },
                    "screenshot_taken_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "When the screenshot was taken."
                    },
                    "abuse_contacts": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/AbuseContact"
                        },
                        "readOnly": true
                    },
                    "blacklist_submissions": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/BlacklistSubmission"
                        },
                        "readOnly": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "abuse_contacts",
                    "blacklist_submissions",
                    "brand_display",
                    "closed_at",
                    "closed_at_source",
                    "created_at",
                    "id",
                    "is_open",
                    "price",
                    "price_currency",
                    "requesting_user_email",
                    "resolution",
                    "resolution_display",
                    "status",
                    "status_display",
                    "target_website",
                    "token_agreed_at",
                    "updated_at"
                ]
            },
            "TakedownCategoryEnum": {
                "enum": [
                    "website",
                    "token"
                ],
                "type": "string",
                "description": "* `website` - Website\n* `token` - Token"
            },
            "TakedownCreate": {
                "type": "object",
                "description": "Serializer for creating new takedown requests.",
                "properties": {
                    "target_website": {
                        "type": "string",
                        "format": "uri",
                        "description": "The target website URL for the takedown request",
                        "maxLength": 500
                    },
                    "user_comment": {
                        "type": "string",
                        "nullable": true,
                        "description": "Optional comment from the requesting user"
                    },
                    "brand": {
                        "type": "string",
                        "format": "uuid",
                        "nullable": true,
                        "description": "Brand associated with this takedown. All users with access to this brand can view the takedown."
                    },
                    "authorization_consent": {
                        "type": "boolean",
                        "writeOnly": true,
                        "description": "The caller confirms they are authorized to request this takedown for the brand. Required (true) for customers once Power of Attorney enforcement is on."
                    },
                    "accepted_price": {
                        "type": "string",
                        "format": "decimal",
                        "pattern": "^-?\\d{0,8}(?:\\.\\d{0,2})?$",
                        "writeOnly": true,
                        "description": "The price per successful takedown the person ordering was shown and accepted (net, VAT on top), from the takedown quote. Send it together with accepted_currency, and only when the quote asks for consent."
                    },
                    "accepted_currency": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/SubscriptionCurrencyEnum"
                            }
                        ],
                        "writeOnly": true,
                        "description": "The currency of accepted_price.\n\n* `USD` - US$\n* `CAD` - CA$\n* `EUR` - EUR"
                    }
                },
                "required": [
                    "target_website"
                ]
            },
            "TakedownEvent": {
                "type": "object",
                "description": "Serializer for takedown event details.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "takedown": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "event_type": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/TakedownEventTypeEnum"
                            }
                        ],
                        "description": "Type of event that occurred\n\n* `STATUS_CHANGED` - Status Changed\n* `ABUSE_REPORT_SENT` - Abuse Report Sent\n* `ABUSE_RESPONSE_RECEIVED` - Abuse Response Received\n* `BLACKLIST_SUBMITTED` - Blacklist Submitted\n* `BLACKLIST_CONFIRMED` - Blacklist Confirmed\n* `DNS_UPDATED` - DNS Records Updated\n* `INFRASTRUCTURE_UPDATED` - Infrastructure Updated\n* `SCREENSHOT_TAKEN` - Screenshot Taken\n* `NOTE` - Note\n* `OTHER` - Other\n* `DOMAIN_RESCANNED` - Domain Rescanned\n* `DOMAIN_MARKED_FALSE_POSITIVE` - Domain Marked False Positive\n* `POST_CLOSE_SKIPPED` - Post-Close Work Skipped"
                    },
                    "event_type_display": {
                        "type": "string",
                        "readOnly": true
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "description": "Human-readable description of the event"
                    },
                    "old_value": {
                        "type": "string",
                        "nullable": true,
                        "description": "Previous value (for status changes, etc.)",
                        "maxLength": 255
                    },
                    "new_value": {
                        "type": "string",
                        "nullable": true,
                        "description": "New value (for status changes, etc.)",
                        "maxLength": 255
                    },
                    "created_by": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true,
                        "nullable": true,
                        "description": "User who created this event (if applicable)"
                    },
                    "created_by_email": {
                        "type": "string",
                        "readOnly": true,
                        "nullable": true
                    },
                    "metadata": {
                        "nullable": true,
                        "description": "Additional event-specific data as JSON"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "created_at",
                    "created_by",
                    "created_by_email",
                    "event_type",
                    "event_type_display",
                    "id",
                    "takedown",
                    "updated_at"
                ]
            },
            "TakedownEventTypeEnum": {
                "enum": [
                    "STATUS_CHANGED",
                    "ABUSE_REPORT_SENT",
                    "ABUSE_RESPONSE_RECEIVED",
                    "BLACKLIST_SUBMITTED",
                    "BLACKLIST_CONFIRMED",
                    "DNS_UPDATED",
                    "INFRASTRUCTURE_UPDATED",
                    "SCREENSHOT_TAKEN",
                    "NOTE",
                    "OTHER",
                    "DOMAIN_RESCANNED",
                    "DOMAIN_MARKED_FALSE_POSITIVE",
                    "POST_CLOSE_SKIPPED"
                ],
                "type": "string",
                "description": "* `STATUS_CHANGED` - Status Changed\n* `ABUSE_REPORT_SENT` - Abuse Report Sent\n* `ABUSE_RESPONSE_RECEIVED` - Abuse Response Received\n* `BLACKLIST_SUBMITTED` - Blacklist Submitted\n* `BLACKLIST_CONFIRMED` - Blacklist Confirmed\n* `DNS_UPDATED` - DNS Records Updated\n* `INFRASTRUCTURE_UPDATED` - Infrastructure Updated\n* `SCREENSHOT_TAKEN` - Screenshot Taken\n* `NOTE` - Note\n* `OTHER` - Other\n* `DOMAIN_RESCANNED` - Domain Rescanned\n* `DOMAIN_MARKED_FALSE_POSITIVE` - Domain Marked False Positive\n* `POST_CLOSE_SKIPPED` - Post-Close Work Skipped"
            },
            "TakedownResolutionEnum": {
                "enum": [
                    "DOMAIN_SUSPENDED",
                    "CONTENT_REMOVED",
                    "SERVER_HOLD",
                    "VOLUNTARY_TAKEDOWN",
                    "UNRESOLVED",
                    "FALSE_POSITIVE",
                    "TOKEN_LISTING_REMOVED",
                    "TOKEN_TRADING_BLOCKED",
                    "TOKEN_WARNING_ADDED"
                ],
                "type": "string",
                "description": "* `DOMAIN_SUSPENDED` - Domain Suspended\n* `CONTENT_REMOVED` - Content Removed\n* `SERVER_HOLD` - Server Hold\n* `VOLUNTARY_TAKEDOWN` - Voluntary Takedown\n* `UNRESOLVED` - Unresolved\n* `FALSE_POSITIVE` - False Positive\n* `TOKEN_LISTING_REMOVED` - Agreed token listing removed\n* `TOKEN_TRADING_BLOCKED` - Trading blocked on agreed platform\n* `TOKEN_WARNING_ADDED` - Token warning added (partial mitigation)"
            },
            "TakedownStatusEnum": {
                "enum": [
                    "REQUESTED",
                    "OPEN",
                    "IN_PROGRESS",
                    "PENDING_RESPONSE",
                    "CLOSED",
                    "FAILED",
                    "REJECTED"
                ],
                "type": "string",
                "description": "* `REQUESTED` - Pending review\n* `OPEN` - Open\n* `IN_PROGRESS` - In Progress\n* `PENDING_RESPONSE` - Pending Response\n* `CLOSED` - Closed\n* `FAILED` - Failed\n* `REJECTED` - Rejected"
            },
            "TierEnum": {
                "enum": [
                    "P1",
                    "P2",
                    "P3"
                ],
                "type": "string",
                "description": "* `P1` - P1 - Immediate (GSB, Netcraft, SmartScreen)\n* `P2` - P2 - Distribution (Spamhaus, Openphish, SpamCop)\n* `P3` - P3 - Prevention (VirusTotal, Symantec, ScamAdviser)"
            },
            "TokenTakedownObjectiveEnum": {
                "enum": [
                    "listing_removed",
                    "trading_blocked"
                ],
                "type": "string",
                "description": "* `listing_removed` - Remove the agreed token listing\n* `trading_blocked` - Block trading on the agreed platform"
            },
            "UserProfile": {
                "type": "object",
                "description": "Serializer for user profile information.",
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid",
                        "readOnly": true
                    },
                    "username": {
                        "type": "string",
                        "description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
                        "pattern": "^[\\w.@+-]+$",
                        "maxLength": 150
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "readOnly": true
                    },
                    "is_active": {
                        "type": "boolean",
                        "readOnly": true,
                        "title": "Active",
                        "description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
                    },
                    "account_type": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/AccountTypeEnum"
                            }
                        ],
                        "readOnly": true,
                        "description": "Multi-brand account tier. Standard users derive their capabilities from the brands they have access to. Partner/Enterprise users have elevated write access across every brand they're a member of.\n\n* `standard` - Standard\n* `partner` - Partner\n* `enterprise` - Enterprise"
                    },
                    "display_plan": {
                        "type": "string",
                        "nullable": true,
                        "readOnly": true
                    },
                    "can_access_billing": {
                        "type": "boolean",
                        "readOnly": true
                    },
                    "can_start_customer_view": {
                        "type": "boolean",
                        "readOnly": true
                    },
                    "features": {
                        "type": "object",
                        "additionalProperties": {
                            "type": "boolean"
                        },
                        "readOnly": true
                    },
                    "two_factor_enabled": {
                        "type": "boolean",
                        "description": "Enable email-based two-factor authentication for this user. Mandatory for staff and superusers."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "readOnly": true
                    }
                },
                "required": [
                    "account_type",
                    "can_access_billing",
                    "can_start_customer_view",
                    "created_at",
                    "display_plan",
                    "email",
                    "features",
                    "id",
                    "is_active",
                    "updated_at",
                    "username"
                ]
            },
            "PaginatedBrandDomainListItemList": {
                "type": "object",
                "required": [
                    "count",
                    "results"
                ],
                "properties": {
                    "count": {
                        "type": "integer",
                        "example": 123
                    },
                    "next": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=4"
                    },
                    "previous": {
                        "type": "string",
                        "nullable": true,
                        "format": "uri",
                        "example": "http://api.example.org/accounts/?page=2"
                    },
                    "results": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/BrandDomainListItem"
                        }
                    }
                }
            },
            "FieldValidationError": {
                "type": "object",
                "minProperties": 1,
                "description": "Field names mapped directly to validation error messages.",
                "additionalProperties": {
                    "anyOf": [
                        {
                            "type": "string"
                        },
                        {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    ]
                },
                "example": {
                    "target_website": [
                        "Target host is not a public address."
                    ]
                }
            },
            "PriceConsentError": {
                "type": "object",
                "description": "A takedown order whose price consent is missing or outdated.",
                "properties": {
                    "code": {
                        "type": "string",
                        "enum": [
                            "price_consent_required",
                            "price_changed"
                        ]
                    },
                    "detail": {
                        "type": "string"
                    },
                    "price": {
                        "type": "object",
                        "properties": {
                            "amount": {
                                "type": "string",
                                "format": "decimal"
                            },
                            "currency": {
                                "type": "string",
                                "enum": [
                                    "EUR",
                                    "USD",
                                    "CAD"
                                ]
                            }
                        },
                        "required": [
                            "amount",
                            "currency"
                        ]
                    }
                },
                "required": [
                    "code",
                    "detail",
                    "price"
                ],
                "example": {
                    "code": "price_changed",
                    "detail": "The price has changed. Show the new price and order again.",
                    "price": {
                        "amount": "400.00",
                        "currency": "EUR"
                    }
                }
            },
            "DuplicateTakedownError": {
                "type": "object",
                "description": "A takedown order for a host that already has an active takedown.",
                "properties": {
                    "code": {
                        "type": "string",
                        "enum": [
                            "duplicate"
                        ]
                    },
                    "detail": {
                        "type": "string"
                    },
                    "takedown_id": {
                        "type": "string",
                        "format": "uuid"
                    }
                },
                "required": [
                    "code",
                    "detail",
                    "takedown_id"
                ],
                "example": {
                    "code": "duplicate",
                    "detail": "A takedown for this website is already active (Open).",
                    "takedown_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
                }
            }
        },
        "securitySchemes": {
            "ApiKeyAuth": {
                "type": "apiKey",
                "in": "header",
                "name": "Authorization",
                "description": "Static API key, sent in the `Authorization` header with the scheme `Api-Key`:\n\n```\nAuthorization: Api-Key nbty_<your_key>\n```\n\nThe key is the whole credential after `Api-Key ` (not `Bearer`). A key belongs to one nebty user and carries that user's current rights, including the right to request takedowns.\n\n**Getting a key.** Brand admins, partner and enterprise accounts with a verified email address create their key in the dashboard under **Settings > API key**. The full key is shown only once, so store it right away. Replacing the key makes the old one stop working at once, and so does revoking it. Creating, replacing and revoking a key work only from the dashboard, not with an API key. If your account cannot create a key, contact nebty.\n\nA missing, revoked or unknown key is answered with `401`."
            }
        }
    },
    "servers": [
        {
            "url": "https://app.nebty.de",
            "description": "Production"
        }
    ],
    "tags": [
        {
            "name": "Brands",
            "description": "The brands you monitor and their headline statistics."
        },
        {
            "name": "Domains",
            "description": "Domains that nebty associated with a brand, with the risk score and verdict computed for that brand."
        },
        {
            "name": "Scans",
            "description": "Scan results for the domains associated with a brand."
        },
        {
            "name": "Takedowns",
            "description": "Takedown cases against infringing websites: list, inspect, follow the event log and request new ones."
        },
        {
            "name": "Account",
            "description": "The user the API key belongs to."
        }
    ]
}
