{
  "openapi": "3.1.1",
  "jsonSchemaDialect": "http://json-schema.org/draft-07/schema#",
  "info": {
    "title": "NE RABOTAET V RF public API v2",
    "version": "2.0.0-draft.2",
    "description": "API v2 pilot contract. Deployment is feature-gated; consult the service release status. Normative semantics.md and profiles.json accompany this contract."
  },
  "servers": [
    {
      "url": "https://nerabotaetv.ru",
      "description": "Public service base URL after pilot activation."
    }
  ],
  "paths": {
    "/api/v2/capabilities": {
      "get": {
        "operationId": "getCapabilities",
        "summary": "Discover current account quotas and location presets",
        "description": "Authenticated; no target requests. Quota values are runtime configuration, not schema defaults.",
        "responses": {
          "200": {
            "description": "Discover current account quotas and location presets",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Capabilities"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {
            "ClientKey": []
          }
        ]
      }
    },
    "/api/v2/profiles": {
      "get": {
        "operationId": "listProfiles",
        "summary": "List immutable measurement profiles",
        "description": "",
        "responses": {
          "200": {
            "description": "List immutable measurement profiles",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/ProfileList"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {},
          {
            "ClientKey": []
          }
        ]
      }
    },
    "/api/v2/probes": {
      "get": {
        "operationId": "listProbes",
        "summary": "List registered source networks and supported profiles",
        "description": "",
        "responses": {
          "200": {
            "description": "List registered source networks and supported profiles",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/ProbeList"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "country_code",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 2,
              "pattern": "^[A-Z]{2}$"
            },
            "required": false,
            "description": ""
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 256
            },
            "required": false,
            "description": ""
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "required": false,
            "description": ""
          }
        ]
      }
    },
    "/api/v2/measurements/latest": {
      "get": {
        "operationId": "getLatestAvailability",
        "summary": "Read last public report for the exact scope",
        "description": "R-10: public scheduled catalog only. Never consult private request history. 404 absent; 200 may be stale; 410 full details expired.",
        "responses": {
          "200": {
            "description": "Read last public report for the exact scope",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Report"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "target",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 2048,
              "minLength": 1
            },
            "required": true,
            "description": "R-01 normalization; read-only."
          },
          {
            "name": "profile",
            "in": "query",
            "schema": {
              "const": "web-basic-v1"
            },
            "required": true,
            "description": ""
          },
          {
            "name": "probe_ids",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "maxLength": 128,
                "minLength": 1,
                "pattern": "^[a-zA-Z0-9_-]+$"
              },
              "minItems": 1,
              "maxItems": 10,
              "uniqueItems": true
            },
            "required": true,
            "description": "Exact probe set, comma-separated. No silent partial selection.",
            "style": "form",
            "explode": false
          },
          {
            "name": "max_age_seconds",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 900,
              "default": 300
            },
            "required": false,
            "description": "Changes eligibility only; never creates a measurement."
          },
          {
            "name": "view",
            "in": "query",
            "schema": {
              "enum": [
                "summary",
                "full"
              ],
              "default": "summary"
            },
            "required": false,
            "description": "Full facts retained 24h; summary excludes observations."
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "required": false,
            "description": "ru or en; defaults to ru."
          }
        ]
      }
    },
    "/api/v2/measurements/{report_id}": {
      "get": {
        "operationId": "getMeasurementReport",
        "summary": "Read public or owned private report",
        "description": "R-04/R-10/R-45. Foreign private and unknown IDs both 404; full after raw expiry 410.",
        "responses": {
          "200": {
            "description": "Read public or owned private report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Report"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "report_id",
            "in": "path",
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 1,
              "pattern": "^[a-zA-Z0-9_-]+$"
            },
            "required": true,
            "description": ""
          },
          {
            "name": "max_age_seconds",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 900,
              "default": 300
            },
            "required": false,
            "description": "Changes eligibility only; never creates a measurement."
          },
          {
            "name": "view",
            "in": "query",
            "schema": {
              "enum": [
                "summary",
                "full"
              ],
              "default": "summary"
            },
            "required": false,
            "description": "Full facts retained 24h; summary excludes observations."
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "required": false,
            "description": "ru or en; defaults to ru."
          }
        ]
      }
    },
    "/api/v2/check-plans": {
      "post": {
        "operationId": "planAvailabilityCheck",
        "summary": "Resolve intent and maximum quota units without starting work",
        "description": "R-13. No target connections or reservations. Account-bound plan valid 120s; no monetary price in this pilot.",
        "responses": {
          "200": {
            "description": "Resolve intent and maximum quota units without starting work",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Plan"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {
            "ClientKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "contract.schema.json#/definitions/CheckIntent"
              }
            }
          }
        }
      }
    },
    "/api/v2/checks": {
      "post": {
        "operationId": "createAvailabilityCheck",
        "summary": "Create or reuse an account-private check",
        "description": "R-11/R-12/R-41. Requires checks:create. Max units is mandatory. Default freshness reuse <=300s. Max_age=0 can join in-flight work. Budget rejection is atomic.",
        "responses": {
          "202": {
            "description": "Queued/running; poll Location with Retry-After.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Check"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum delay in seconds before polling/retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              },
              "Location": {
                "description": "URL of the created check.",
                "schema": {
                  "type": "string",
                  "maxLength": 2048,
                  "format": "uri-reference"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          },
          "200": {
            "description": "Completed cache reuse or replay of a terminal check.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Check"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "URL of the created check.",
                "schema": {
                  "type": "string",
                  "maxLength": 2048,
                  "format": "uri-reference"
                }
              }
            }
          }
        },
        "security": [
          {
            "ClientKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "contract.schema.json#/definitions/CheckRequest"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 16
            },
            "required": true,
            "description": "R-12 or R-31. Opaque retry key; do not put credentials here."
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "required": false,
            "description": "ru or en; defaults to ru."
          }
        ]
      }
    },
    "/api/v2/checks/{check_id}": {
      "get": {
        "operationId": "getAvailabilityCheck",
        "summary": "Read owned check and partial or terminal report",
        "description": "R-14: completed/expired/failed are terminal; target failure is a result, not an API error. Server finalizes without polling. Foreign ID 404.",
        "responses": {
          "200": {
            "description": "Read owned check and partial or terminal report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Check"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Minimum delay in seconds before polling/retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 0
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "check_id",
            "in": "path",
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 1,
              "pattern": "^[a-zA-Z0-9_-]+$"
            },
            "required": true,
            "description": ""
          },
          {
            "name": "max_age_seconds",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 900,
              "default": 300
            },
            "required": false,
            "description": "Changes eligibility only; never creates a measurement."
          },
          {
            "name": "view",
            "in": "query",
            "schema": {
              "enum": [
                "summary",
                "full"
              ],
              "default": "summary"
            },
            "required": false,
            "description": "Full facts retained 24h; summary excludes observations."
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "required": false,
            "description": "ru or en; defaults to ru."
          }
        ]
      }
    },
    "/api/v2/catalogue": {
      "get": {
        "operationId": "listCatalogue",
        "summary": "Operator-maintained root catalogue, including sites without v2 observations",
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253,
              "pattern": "^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current projection; observation times and freshness are independent of publication time.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/CataloguePage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "description": "R-04b/R-27a. Uses the canonical report projector with max_age=300 seconds. Observation age is evaluated from original completion timestamps, independently of the nominal collection interval, response delivery and cache reads. A scheduled refresh does not extend freshness. Historical status and current freshness must be read together; GET never starts a measurement."
      }
    },
    "/api/v2/catalogue/{domain}": {
      "get": {
        "operationId": "catalogueHistory",
        "summary": "Completed public operator observations, newest first",
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253,
              "pattern": "^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 1,
              "pattern": "^[a-zA-Z0-9_-]+$"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current projection; observation times and freshness are independent of publication time.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/CatalogueHistory"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "description": "R-04b/R-27a. Uses the canonical report projector with max_age=300 seconds. Observation age is evaluated from original completion timestamps, independently of the nominal collection interval, response delivery and cache reads. A scheduled refresh does not extend freshness. Historical status and current freshness must be read together; GET never starts a measurement."
      }
    },
    "/api/v2/publications": {
      "get": {
        "operationId": "listPublications",
        "summary": "Root summaries explicitly published by their owners",
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 1,
              "pattern": "^[a-zA-Z0-9_-]+$"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Masked publication_version=2. status is historical at observed_at. No full domain/URL, even when authenticated; owners read their original private measurement separately.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/PublicationPage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v2/checks/{check_id}/publication": {
      "post": {
        "operationId": "publishCheck",
        "summary": "Explicitly publish a completed HTTPS-root check summary",
        "security": [
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "check_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 1,
              "pattern": "^[a-zA-Z0-9_-]+$"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Masked publication_version=2. status is historical at observed_at. No full domain/URL, even when authenticated; owners read their original private measurement separately.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Publication"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "description": "Requires checks:create and ownership. Only completed web-basic-v1 HTTPS roots without query; otherwise 422. Explicit empty object consent. Idempotent while visible; published_at unchanged. Hidden/withdrawn publications return 404; retry cannot restore them. Blocked domains return 403. UTC-day limits: 5/account, 20/network, 5/exact domain, 200 globally; exhaustion returns 429 Retry-After. Retention unchanged. Deterministic mask replaces three central registrable-name characters with *** and omits subdomains; short/IDN names fully masked. Not anonymization or assurance of legality. Breaking pilot format: publication_version=2 replaces the previous nested report.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "contract.schema.json#/definitions/PublishRequest"
              }
            }
          }
        }
      }
    },
    "/api/v2/publications/{publication_id}": {
      "get": {
        "operationId": "getPublication",
        "summary": "Masked historical summary only; no full address, observations or redirects",
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "publication_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 1,
              "pattern": "^[a-zA-Z0-9_-]+$"
            }
          },
          {
            "name": "Accept-Language",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Masked publication_version=2. status is historical at observed_at. No full domain/URL, even when authenticated; owners read their original private measurement separately.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/Publication"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v2/abuse-reports": {
      "post": {
        "operationId": "reportAbuse",
        "summary": "Report a publication or catalogue entry to a private moderation queue",
        "description": "subject_id is publication_id or listed catalogue domain. No files, free text or external fetches. child_safety=true only for suspected_illegal. Deduplicated per reporter/subject. UTC-day limits: 3/reporter, 10/network across keys and sessions, 1000 globally; 429 Retry-After. Ordinary reports do not remove content. Child-safety reports temporarily hide user publications for human review, not a permanent domain ban. Catalogue decisions require an operator. Receipt confirms intake only.",
        "security": [
          {},
          {
            "ClientKey": []
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "contract.schema.json#/definitions/AbuseRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/AbuseReceipt"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v2/publications/{publication_id}/withdraw": {
      "post": {
        "operationId": "withdrawPublication",
        "summary": "Owner withdraws a publication",
        "description": "Requires checks:create and ownership. Idempotent empty JSON object. Subsequent public reads hide the publication; private report lifetime unchanged. Does not undo external copies.",
        "security": [
          {
            "ClientKey": []
          }
        ],
        "parameters": [
          {
            "name": "publication_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 128,
              "minLength": 1,
              "pattern": "^[a-zA-Z0-9_-]+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "contract.schema.json#/definitions/PublishRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/PublicationWithdrawal"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v2/activity": {
      "get": {
        "operationId": "getVisitorActivity",
        "summary": "Recent visitor activity; private entries expose only an opaque activity ID and creation time",
        "security": [],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20,
              "default": 6
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recent visitor activity; private entries expose only an opaque activity ID and creation time",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/ActivityPage"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    },
    "/api/v2/catalogue/{domain}/browser-observations": {
      "get": {
        "operationId": "getBrowserObservationSummary",
        "summary": "Unverified browser signals in the last 24 hours; never included in probe availability",
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 253
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Unverified browser signals in the last 24 hours; never included in probe availability",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "contract.schema.json#/definitions/BrowserObservationSummary"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/Problem"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ClientKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Per-account key; scopes measurements:read and checks:create. Not an origin or probe credential."
      }
    },
    "responses": {
      "Problem": {
        "description": "R-16 Problem Details. Status equals HTTP response status.",
        "headers": {
          "Retry-After": {
            "description": "Minimum delay in seconds before polling/retrying.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "contract.schema.json#/definitions/Problem"
            }
          }
        }
      }
    }
  }
}
