{
  "openapi": "3.1.0",
  "info": {
    "title": "VK.watch API",
    "version": "1.0.0",
    "description": "Historical VK profile data: snapshots, changes over time, friends, photos, comments, faceted search and face search. Every request is authenticated with an API key and charged in credits (x-credits on each operation): API pack credits first, or site credits at the same prices when the account holds no usable API credits (X-Credits-Wallet says which). A failed request is refunded. Responses are JSON envelopes {response, meta} except /search, /geo/* and /facets/*, which are returned unwrapped."
  },
  "servers": [{ "url": "https://api.vk.watch/v1" }],
  "security": [{ "bearerAuth": [] }],
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "description": "API key created at https://vk.watch/me/api-keys (vkw_…)" }
    },
    "headers": {
      "X-Credits-Charged": { "schema": { "type": "integer" }, "description": "Credits charged for this request (0 after a refund)." },
      "X-Credits-Remaining": { "schema": { "type": "integer" }, "description": "Credits left in the wallet that paid." },
      "X-Credits-Wallet": { "schema": { "type": "string", "enum": ["api", "ui"] }, "description": "Wallet that paid: api (API pack credits) or ui (site credits)." },
      "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Requests per second per key." }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string", "enum": ["apiKeyRequired", "apiKeyInvalid", "apiAccessExpired", "apiCreditsExhausted", "apiRateLimited", "profileNotFound", "invalidProfileId", "invalidParameters"] },
              "statusCode": { "type": "integer" },
              "params": { "type": "object", "additionalProperties": true }
            }
          }
        }
      },
      "Envelope": {
        "type": "object",
        "properties": {
          "response": { "description": "Route payload" },
          "meta": {
            "type": "object",
            "properties": { "credits": { "type": "object", "properties": { "charged": { "type": "integer" }, "remaining": { "type": "integer" }, "wallet": { "type": "string", "enum": ["api", "ui"], "nullable": true } } } }
          }
        }
      }
    },
    "parameters": {
      "profileId": { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" }, "description": "VK user id" }
    },
    "responses": {
      "Unauthorized": { "description": "Missing or revoked key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "PaymentRequired": { "description": "No API access window or not enough credits; nothing charged", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "Unknown profile; nothing charged", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "RateLimited": { "description": "Rate limit exceeded; retry after one second", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Envelope": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } }
    }
  },
  "paths": {
    "/me": { "get": { "summary": "Key owner balance, prices and limits", "x-credits": 0, "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "401": { "$ref": "#/components/responses/Unauthorized" } } } },
    "/profile/{id}": { "get": { "summary": "Latest profile snapshot with counts", "x-credits": 2, "parameters": [{ "$ref": "#/components/parameters/profileId" }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } } } },
    "/profile/{id}/changes": { "get": { "summary": "Field changes over time", "x-credits": 2, "parameters": [{ "$ref": "#/components/parameters/profileId" }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/profile/{id}/snapshots": { "get": { "summary": "List of stored snapshots", "x-credits": 1, "parameters": [{ "$ref": "#/components/parameters/profileId" }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/profile/{id}/snapshot/{snapshotId}": { "get": { "summary": "One historical snapshot", "x-credits": 2, "parameters": [{ "$ref": "#/components/parameters/profileId" }, { "name": "snapshotId", "in": "path", "required": true, "schema": { "type": "string" } }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/profile/{id}/friends": { "get": { "summary": "Friend list", "x-credits": 2, "parameters": [{ "$ref": "#/components/parameters/profileId" }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/profile/{id}/photos": { "get": { "summary": "Photos (URLs are signed proxy links)", "x-credits": 2, "parameters": [{ "$ref": "#/components/parameters/profileId" }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/profile/{id}/comments": { "get": { "summary": "Comments", "x-credits": 1, "parameters": [{ "$ref": "#/components/parameters/profileId" }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/profile/{id}/identity": { "get": { "summary": "Name and userpic only", "x-credits": 1, "parameters": [{ "$ref": "#/components/parameters/profileId" }], "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" }, "404": { "$ref": "#/components/responses/NotFound" } } } },
    "/search": { "get": { "summary": "Faceted profile search (unwrapped response: results, total, has_more, facets)", "x-credits": 1, "parameters": [{ "name": "name", "in": "query", "schema": { "type": "string" } }, { "name": "page", "in": "query", "schema": { "type": "integer", "default": 0 } }, { "name": "city", "in": "query", "schema": { "type": "string" } }, { "name": "country", "in": "query", "schema": { "type": "string" } }, { "name": "bdate_year", "in": "query", "schema": { "type": "integer" } }], "responses": { "200": { "description": "OK" }, "402": { "$ref": "#/components/responses/PaymentRequired" } } } },
    "/lookup": { "post": { "summary": "Resolve one id or screen name to a profile", "x-credits": 1, "requestBody": { "content": { "application/json": { "schema": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string", "description": "Numeric VK id or screen name, e.g. durov" } } } } } }, "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" } } } },
    "/geo/search": { "get": { "summary": "City and country suggestions", "x-credits": 0, "parameters": [{ "name": "q", "in": "query", "schema": { "type": "string" } }], "responses": { "200": { "$ref": "#/components/responses/Envelope" } } } },
    "/geo/resolve": { "get": { "summary": "Resolve a geo id", "x-credits": 0, "responses": { "200": { "$ref": "#/components/responses/Envelope" } } } },
    "/facets/suggest": { "get": { "summary": "Facet value suggestions", "x-credits": 0, "responses": { "200": { "$ref": "#/components/responses/Envelope" } } } },
    "/faces": { "post": { "summary": "Face search by photo (JPEG/PNG up to 20 MB, field `photo`)", "x-credits": 20, "requestBody": { "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "photo": { "type": "string", "format": "binary" } }, "required": ["photo"] } } } }, "responses": { "200": { "$ref": "#/components/responses/Envelope" }, "402": { "$ref": "#/components/responses/PaymentRequired" } } } }
  }
}
