{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Kevmi — server API",
    "version": "2026-10-22.12",
    "description": "Kevmi API: Telegram sign-in, sessions, merchant invoices, encrypted buyer checkout, support, notifications, applications and webhook delivery. One-time direct payments only. JSON responses use no-store. Timestamps are UTC Unix milliseconds unless stated otherwise. Live checkout uses a configured external gateway; card and bank-code fields are encrypted in the browser and decrypted only by the gateway. New charges require the latest merchant website application to be approved. Creating an invoice does not charge a buyer.",
    "x-updated-at": "2026-10-22"
  },
  "servers": [
    {
      "url": "https://kevmi.one",
      "description": "The public project origin; the hosting platform may apply additional access controls."
    }
  ],
  "externalDocs": {
    "description": "Public product documentation",
    "url": "https://kevmi.one/docs"
  },
  "tags": [
    {
      "name": "Service",
      "description": "Public service status."
    },
    {
      "name": "Auth",
      "description": "Registration and sign-in share the verified Telegram flow."
    },
    {
      "name": "Account",
      "description": "Settings for the current user only."
    },
    {
      "name": "Payment links",
      "description": "Server invoices for the current store. The price, currency, VAT payer, seller name and calculation are immutable."
    },
    {
      "name": "Checkout",
      "description": "Read one invoice without an account. Payment availability is checked separately."
    },
    {
      "name": "Support",
      "description": "Public knowledge base and the current user's support requests."
    },
    {
      "name": "Notifications",
      "description": "Account event center, website read state and independent Telegram delivery status."
    },
    {
      "name": "Telegram",
      "description": "Bot webhook; not a payment webhook."
    },
    {
      "name": "Disabled payments",
      "description": "Unsupported legacy money routes and payout execution. The public checkout flow has its own documented endpoints."
    },
    {
      "name": "Merchant API",
      "description": "Scoped server-to-server invoices and immutable event history."
    },
    {
      "name": "Webhooks",
      "description": "Verified HTTPS endpoints, signed events, delivery attempts and retries."
    },
    {
      "name": "Applications",
      "description": "Authenticated website applications and individual tracking."
    },
    {
      "name": "Moderation",
      "description": "Allowlisted Telegram moderators; every decision is version-checked."
    },
    {
      "name": "Gateway events",
      "description": "Source-native gateway events are verified, then the authoritative payment is read over authenticated server transport. Merchant-facing webhooks use a separate signature and delivery queue."
    }
  ],
  "security": [],
  "x-disabled-route-prefixes": [
    "/api/payments",
    "/api/payouts",
    "/api/gateway",
    "/api/linzapay"
  ],
  "x-disabled-route-behavior": "Legacy unscoped direct-money routes and payout execution remain disabled. Authenticated /api/v1/payments creates invoices; /api/checkout/{token} exposes the separate buyer checkout flow. POST /api/gateway/webhook accepts signed gateway events.",
  "paths": {
    "/api/config": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "getConfig",
        "summary": "Current integration readiness",
        "responses": {
          "200": {
            "description": "Configuration without secrets.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Config"
                }
              }
            }
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "getHealth",
        "summary": "API and D1 table status",
        "description": "not_configured can have status=ok: public pages and search can run without DB. A configured DB with unavailable tables returns 503/degraded. This response does not test Telegram or model network connectivity.",
        "responses": {
          "200": {
            "description": "Storage is ready or not_configured.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          },
          "503": {
            "description": "D1 is unavailable or an unexpected service error occurred.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Health"
                    },
                    {
                      "$ref": "#/components/schemas/Error"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "operationId": "getCurrentSession",
        "summary": "Current session and CSRF",
        "security": [
          {},
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "authenticated=false when no valid session exists.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Anonymous"
                    },
                    {
                      "$ref": "#/components/schemas/CurrentSession"
                    }
                  ]
                }
              }
            }
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/auth/telegram/start": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "startTelegramLogin",
        "summary": "Start sign-in or registration",
        "description": "Creates a 300-second challenge and an HttpOnly browser-proof cookie; at most six starts per minute per hashed address. Compare the six-digit code on the website and in the private bot chat.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Sign-in request created; the proof cookie binds it to the original browser.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "Secure; HttpOnly; SameSite=Lax; Path=/. JavaScript cannot access the session value. Completing sign-in also clears the browser-proof cookie."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginChallenge"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/auth/telegram/complete": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "completeTelegramLogin",
        "summary": "Complete a verified sign-in",
        "description": "Requires the proof cookie from start and the same browser. Pending returns 202. After bot confirmation, the request issues one 24-hour session. Up to 90 checks per minute per challenge. A client-supplied Telegram ID is not accepted.",
        "security": [
          {
            "browserProof": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "challengeId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{43}$"
                  }
                },
                "required": [
                  "challengeId"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account created or updated and session issued.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "Secure; HttpOnly; SameSite=Lax; Path=/. JavaScript cannot access the session value. Completing sign-in also clears the browser-proof cookie."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompletedLogin"
                }
              }
            }
          },
          "202": {
            "description": "Awaiting confirmation in Telegram.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "const": "pending"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The five-minute sign-in request expired.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_EXPIRED"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "logoutCurrentSession",
        "summary": "End the current session",
        "description": "No body is required or read. The bot's /logout command separately ends all account sessions.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session removed and cookie cleared.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Set-Cookie": {
                "schema": {
                  "type": "string"
                },
                "description": "Secure; HttpOnly; SameSite=Lax; Path=/. JavaScript cannot access the session value. Completing sign-in also clears the browser-proof cookie."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "loggedOut": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "loggedOut"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/account/settings": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccountSettings",
        "summary": "Current user settings",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Public fields of the current user's profile.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserResponse"
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Account"
        ],
        "operationId": "updateAccountSettings",
        "summary": "Change the store name, VAT payer or notifications",
        "description": "All fields are optional: partial patch. Saving vatPayer does not create a financial operation. The payments and payouts switches control preferences, not gateway availability.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettingsPatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated profile.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/support/ask": {
      "post": {
        "tags": [
          "Support"
        ],
        "operationId": "askDocumentation",
        "summary": "Answer from the complete public knowledge base",
        "description": "Public question without a session or CSRF. A supplied Origin must match APP_ORIGIN; agents can omit it. In AI mode, the server sends all published articles, facts, page catalog and feature readiness. Optional history and pageContext are untrusted question context. The model cannot access accounts, money, private requests or tools. With D1, the limit is 12 questions per minute per hashed address. AI requires D1, valid provider configuration and quota: 60 generations per hour service-wide by default. Configuration readiness does not prove external API availability. Provider errors, quota exhaustion or invalid output return search with aiUnavailable=true and HTTP 200. Without generation configuration, regular search is returned.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": false,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object up to 65,536 bytes. Unknown fields are rejected. Text lengths are checked after trim.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SupportQuestion"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "An answer or matching documentation with validated article links.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupportAnswer"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/support/tickets": {
      "get": {
        "tags": [
          "Support"
        ],
        "operationId": "listOwnTickets",
        "summary": "The latest 30 owned support requests",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first by createdAt; returns the latest 30 records.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tickets": {
                      "type": "array",
                      "maxItems": 30,
                      "items": {
                        "$ref": "#/components/schemas/Ticket"
                      }
                    }
                  },
                  "required": [
                    "tickets"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Support"
        ],
        "operationId": "createOwnTicket",
        "summary": "Save a support request",
        "description": "Up to six requests per user per hour, shared by the website and bot. Saving creates an account record. Keep its reference to ask about status.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "subject": {
                    "type": "string",
                    "minLength": 1,
                    "x-trimmedMaxLength": 120,
                    "x-trimmedMinLength": 1,
                    "description": "Surrounding spaces are trimmed. Length after trim: 1–120 characters. Control characters except tabs and line breaks are forbidden."
                  },
                  "message": {
                    "type": "string",
                    "minLength": 5,
                    "x-trimmedMaxLength": 4000,
                    "x-trimmedMinLength": 5,
                    "description": "Surrounding spaces are trimmed. Length after trim: 5–4,000 characters. Control characters except tabs and line breaks are forbidden."
                  }
                },
                "required": [
                  "subject",
                  "message"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Support request saved.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/support/tickets/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^tkt_[a-f0-9-]{36}$"
          },
          "description": "Identifier of an owned support request."
        }
      ],
      "get": {
        "tags": [
          "Support"
        ],
        "operationId": "getOwnTicket",
        "summary": "Read an owned support request",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Another user's request and a missing request both return 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketResponse"
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Support"
        ],
        "operationId": "closeOwnTicket",
        "summary": "Close an owned support request",
        "description": "The only allowed change is status=closed. This API does not reopen requests, edit messages or submit operator replies.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "const": "closed"
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Support request closed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "closed": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "closed"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/notifications": {
      "get": {
        "tags": [
          "Notifications"
        ],
        "operationId": "listOwnNotifications",
        "summary": "A page of owned notifications",
        "description": "Up to 30 records, sorted by createdAt DESC then id DESC. Listing does not change readAt or trigger delivery. unreadCount is the current user's total unread count across pages. Owner fields, Telegram ID and secrets are excluded.",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "unread",
            "in": "query",
            "description": "1 selects unread only; 0 or an omitted value selects all events.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ],
              "default": "0"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "nextCursor from the previous response. Pass unchanged through URLSearchParams; format createdAt:id, with createdAt a safe integer in milliseconds.",
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,16}:ntf_[A-Za-z0-9-]{1,80}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Events with independent read and delivery states.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationsPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/notifications/read": {
      "patch": {
        "tags": [
          "Notifications"
        ],
        "operationId": "markOwnNotificationsRead",
        "summary": "Mark owned notifications as read",
        "description": "Accepts either ids, or all:true together with before. before is the time of the last observed event and cannot exceed server time. Newer events remain unread. The request is idempotent: existing readAt values do not change. Other users' and missing IDs are neither modified nor disclosed. Telegram status and sentAt remain unchanged.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReadNotifications"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The number of newly read events, operation time and current unread count.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadNotificationsResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/notifications/test": {
      "post": {
        "tags": [
          "Notifications"
        ],
        "operationId": "testOwnNotification",
        "summary": "Send a test notification to the account's Telegram",
        "description": "Queues a message and attempts delivery. At most three per user per hour. The test is not a payment notification and does not change a balance. HTTP 202 does not confirm delivery; check the notification list.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Queueing result.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "queued": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "queued"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/telegram/webhook": {
      "post": {
        "tags": [
          "Telegram"
        ],
        "operationId": "receiveTelegramUpdate",
        "summary": "Receive a Telegram Bot API event",
        "description": "Requires only the Telegram secret header, without session, CSRF or Origin. Additional Update fields are allowed. Handles message and callback_query; personal actions require the verified sender's private chat. Other updates are skipped. update_id is deduplicated; an in-progress update returns 503 for retry. This is not a payment-provider webhook.",
        "security": [
          {
            "telegramWebhookSecret": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Telegram Update, maximum 65,536 bytes.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TelegramUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Processed, skipped or already handled.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "ok"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Telegram request failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TELEGRAM_UNAVAILABLE",
              "TELEGRAM_INVALID_RESPONSE",
              "TELEGRAM_RATE_LIMITED",
              "TELEGRAM_DELIVERY_FAILED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/payments": {
      "post": {
        "tags": [
          "Disabled payments"
        ],
        "operationId": "paymentsUnavailable",
        "summary": "Financial operation unavailable",
        "description": "Returns 503 GATEWAY_NOT_CONNECTED. Financial operations are unavailable. The body is not processed and no gateway request is made.",
        "security": [],
        "responses": {
          "503": {
            "description": "Financial operations are unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "const": "GATEWAY_NOT_CONNECTED"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "error"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        }
      }
    },
    "/api/payouts": {
      "post": {
        "tags": [
          "Disabled payments"
        ],
        "operationId": "payoutsUnavailable",
        "summary": "Financial operation unavailable",
        "description": "Returns 503 GATEWAY_NOT_CONNECTED. Financial operations are unavailable. The body is not processed and no gateway request is made.",
        "security": [],
        "responses": {
          "503": {
            "description": "Financial operations are unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "const": "GATEWAY_NOT_CONNECTED"
                        },
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "code",
                        "message"
                      ],
                      "additionalProperties": false
                    }
                  },
                  "required": [
                    "error"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "Service"
        ],
        "operationId": "getOpenApi",
        "summary": "Public machine-readable contract",
        "description": "Read only. Contains no secrets, sessions, user records or operational payment-provider contract.",
        "responses": {
          "200": {
            "description": "This OpenAPI 3.1 document.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "public, max-age=300"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "openapi",
                    "info",
                    "paths"
                  ],
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/api/payment-links": {
      "get": {
        "tags": [
          "Payment links"
        ],
        "operationId": "listOwnPaymentLinks",
        "summary": "List owned payment links",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "description": "Sorted by createdAt DESC, id DESC. Public links work across devices; listing requires an account.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nextCursor from the previous response. The service uses base64 JSON [createdAt,id]; pass it unchanged through URLSearchParams."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of owned payment links.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinksPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Payment links"
        ],
        "operationId": "createOwnPaymentLink",
        "summary": "Create an invoice with immutable terms",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "One key per logical request. A repeat with identical canonical input returns the original record; different input with the same key returns 409."
          }
        ],
        "description": "Create an immutable invoice and immediately receive checkoutUrl; this does not charge the buyer. USD: card/Alipay; RUB: SBP; USDT: crypto. USD crypto remains accepted for compatibility but cannot be paid without a USDT invoice. Fee and VAT customer shares are independent integers from 0 to 100; current live card/Alipay supports VAT customer=100 and fee customer=0. The customer total is never silently changed. Latest website application must be approved before a new live charge. Invoice creation and its merchant event commit atomically.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentLink"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay; replayed=true.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "201": {
            "description": "Invoice created; replayed=false.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/payment-links/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "description": "Owned link identifier, not the public token."
        }
      ],
      "get": {
        "tags": [
          "Payment links"
        ],
        "operationId": "getOwnPaymentLink",
        "summary": "Owned link and saved calculation",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Another user's ID and a missing ID both return 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Payment links"
        ],
        "operationId": "changePaymentLinkStatus",
        "summary": "Pause, resume or cancel a link",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "description": "Changes only status. The update and immutable invoice.updated event commit atomically. Concurrent changes use a version check; refresh and retry on LINK_CHANGED. cancelled is terminal, expiration is never extended, and price, methods, cost shares and description stay frozen. Repeating the saved status returns the current invoice.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current state of the owned link.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Random public identifier from the checkout URL. Grants read access to this invoice only."
        }
      ],
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getPublicCheckout",
        "summary": "Public invoice details for the customer",
        "description": "Read the immutable public invoice quote and its persisted payment snapshot. method must belong to the invoice. No account is required. Does not expose owner identity, private metadata or merchant proceeds. The token grants access only to this checkout. availability reflects configuration, allocation, technical limits and merchant approval; payment confirmation is separate.",
        "parameters": [
          {
            "name": "method",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "card",
                "alipay",
                "sbp",
                "crypto"
              ]
            },
            "description": "Must be present in the invoice's saved methods."
          }
        ],
        "responses": {
          "200": {
            "description": "Public invoice and the existing payment, if dispatched.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invoice": {
                      "$ref": "#/components/schemas/CheckoutInvoice"
                    },
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "invoice",
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/pay": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Random public identifier from the checkout URL. Grants read access to this invoice only."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "startCheckoutPayment",
        "summary": "Start or recover the invoice payment",
        "description": "Same-origin buyer operation; no account or CSRF token required. The server reserves one operation and a stable idempotency key before gateway dispatch. A repeat recovers the same operation; a lost response must be resolved through status. The payment method locks after dispatch. Card data must be browser-encrypted with a fresh payment intent. SBP/crypto send the saved customer total; card/Alipay use the supported immutable tax configuration. New charges require an approved merchant application. Existing dispatched payments can be recovered after invoice expiration, pause or approval changes. No /v2 or hosted-card route is used.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartCheckoutPayment"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing operation recovered; no second payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "202": {
            "description": "Operation dispatched; completion is asynchronous.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/v1/payments": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listOwnPaymentLinksViaPayments",
        "summary": "List owned payment links",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "description": "Sorted by createdAt DESC, id DESC. Public links work across devices; listing requires an account.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nextCursor from the previous response. The service uses base64 JSON [createdAt,id]; pass it unchanged through URLSearchParams."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of owned payment links.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinksPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:read"
      },
      "post": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "createOwnPaymentLinkViaPayments",
        "summary": "Create an invoice with immutable terms",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "One key per logical request. A repeat with identical canonical input returns the original record; different input with the same key returns 409."
          }
        ],
        "description": "Create an immutable invoice and immediately receive checkoutUrl; this does not charge the buyer. USD: card/Alipay; RUB: SBP; USDT: crypto. USD crypto remains accepted for compatibility but cannot be paid without a USDT invoice. Fee and VAT customer shares are independent integers from 0 to 100; current live card/Alipay supports VAT customer=100 and fee customer=0. The customer total is never silently changed. Latest website application must be approved before a new live charge. Invoice creation and its merchant event commit atomically.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentLink"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay; replayed=true.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "201": {
            "description": "Invoice created; replayed=false.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/v1/payments/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "description": "Owned link identifier, not the public token."
        }
      ],
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "getOwnPaymentLinkViaPayments",
        "summary": "Owned link and saved calculation",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Another user's ID and a missing ID both return 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "parameters": [],
        "x-required-scope": "invoices:read"
      },
      "patch": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "changePaymentLinkStatusViaPayments",
        "summary": "Pause, resume or cancel a link",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [],
        "description": "Changes only status. The update and immutable invoice.updated event commit atomically. Concurrent changes use a version check; refresh and retry on LINK_CHANGED. cancelled is terminal, expiration is never extended, and price, methods, cost shares and description stay frozen. Repeating the saved status returns the current invoice.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current state of the owned link.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/v1/payment-links": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listOwnPaymentLinksViaLinks",
        "summary": "List owned payment links",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "description": "Sorted by createdAt DESC, id DESC. Public links work across devices; listing requires an account.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "nextCursor from the previous response. The service uses base64 JSON [createdAt,id]; pass it unchanged through URLSearchParams."
          }
        ],
        "responses": {
          "200": {
            "description": "A page of owned payment links.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinksPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:read"
      },
      "post": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "createOwnPaymentLinkViaLinks",
        "summary": "Create an invoice with immutable terms",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "One key per logical request. A repeat with identical canonical input returns the original record; different input with the same key returns 409."
          }
        ],
        "description": "Create an immutable invoice and immediately receive checkoutUrl; this does not charge the buyer. USD: card/Alipay; RUB: SBP; USDT: crypto. USD crypto remains accepted for compatibility but cannot be paid without a USDT invoice. Fee and VAT customer shares are independent integers from 0 to 100; current live card/Alipay supports VAT customer=100 and fee customer=0. The customer total is never silently changed. Latest website application must be approved before a new live charge. Invoice creation and its merchant event commit atomically.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePaymentLink"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Idempotent replay; replayed=true.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "201": {
            "description": "Invoice created; replayed=false.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/v1/payment-links/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "description": "Owned link identifier, not the public token."
        }
      ],
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "getOwnPaymentLinkViaLinks",
        "summary": "Owned link and saved calculation",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Another user's ID and a missing ID both return 404.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "parameters": [],
        "x-required-scope": "invoices:read"
      },
      "patch": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "changePaymentLinkStatusViaLinks",
        "summary": "Pause, resume or cancel a link",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [],
        "description": "Changes only status. The update and immutable invoice.updated event commit atomically. Concurrent changes use a version check; refresh and retry on LINK_CHANGED. cancelled is terminal, expiration is never extended, and price, methods, cost shares and description stay frozen. Repeating the saved status returns the current invoice.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current state of the owned link.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentLinkResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "invoices:write"
      }
    },
    "/api/api-keys": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listMerchantKeys",
        "summary": "List own key metadata",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Secrets and secret hashes are omitted.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MerchantKey"
                      }
                    }
                  },
                  "required": [
                    "keys"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "createMerchantKey",
        "summary": "Create a scoped key; reveal its secret once",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "description": "Maximum 10 active keys. At most 5 creations/hour/user. Keys expire, can be revoked and are rate-limited to 90 API requests/minute/key.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 60
                  },
                  "scopes": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 3,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "enum": [
                        "invoices:read",
                        "invoices:write",
                        "events:read"
                      ]
                    }
                  },
                  "expiresInDays": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 365,
                    "default": 90
                  }
                },
                "required": [
                  "name"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Store the secret securely on your server.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "$ref": "#/components/schemas/MerchantKey"
                    },
                    "secret": {
                      "type": "string",
                      "pattern": "^kv_live_[A-Za-z0-9_-]{43}$"
                    }
                  },
                  "required": [
                    "key",
                    "secret"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/api-keys/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^key_[0-9a-f-]{36}$"
          }
        }
      ],
      "delete": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "revokeMerchantKey",
        "summary": "Revoke own key",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Future uses of the key are rejected.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "revoked": {
                      "const": true
                    }
                  },
                  "required": [
                    "revoked"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/events": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listOwnEvents",
        "summary": "Read own immutable event history",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "description": "Unix timestamp in milliseconds, UTC."
            },
            "description": "Legacy exclusive timestamp boundary. Cannot be combined with cursor. Use nextCursor for lossless pagination."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque nextCursor returned by the previous page. Encodes [createdAt,id] and preserves events sharing one timestamp."
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first; up to 50 events. Follow nextCursor until null.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "maxItems": 50,
                      "items": {
                        "$ref": "#/components/schemas/MerchantEvent"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "events",
                    "nextCursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/v1/events": {
      "get": {
        "tags": [
          "Merchant API"
        ],
        "operationId": "listMerchantEventsWithKey",
        "summary": "Read own immutable event history",
        "security": [
          {
            "merchantKey": []
          }
        ],
        "parameters": [
          {
            "name": "before",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "description": "Unix timestamp in milliseconds, UTC."
            },
            "description": "Legacy exclusive timestamp boundary. Cannot be combined with cursor. Use nextCursor for lossless pagination."
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque nextCursor returned by the previous page. Encodes [createdAt,id] and preserves events sharing one timestamp."
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first; up to 50 events. Follow nextCursor until null.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "events": {
                      "type": "array",
                      "maxItems": 50,
                      "items": {
                        "$ref": "#/components/schemas/MerchantEvent"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "events",
                    "nextCursor"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        },
        "x-required-scope": "events:read"
      }
    },
    "/api/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "listWebhookEndpoints",
        "summary": "List endpoints and last 30 deliveries",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "No signing secrets are returned.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    },
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "available": {
                      "type": "boolean"
                    },
                    "eventTypes": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "invoice.created",
                          "invoice.updated",
                          "payment.succeeded",
                          "payment.failed",
                          "payment.refunded",
                          "payment.partially_refunded",
                          "payment.disputed",
                          "payment.review_required"
                        ]
                      }
                    }
                  },
                  "required": [
                    "endpoints",
                    "deliveries",
                    "available",
                    "eventTypes"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "createWebhookEndpoint",
        "summary": "Register a public HTTPS destination",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "description": "Up to 5 endpoints and 6 creations/hour/user. Public HTTPS domains only; no credentials, IP literals or custom ports. A newly created endpoint receives no live deliveries until its challenge succeeds.",
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 8,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "enum": [
                        "invoice.created",
                        "invoice.updated",
                        "payment.succeeded",
                        "payment.failed",
                        "payment.refunded",
                        "payment.partially_refunded",
                        "payment.disputed",
                        "payment.review_required"
                      ]
                    }
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Save the one-time signing secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoint": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "secret": {
                      "type": "string",
                      "pattern": "^whsec_[A-Za-z0-9_-]{43}$",
                      "description": "Shown only on create/rotate. Stored encrypted server-side."
                    }
                  },
                  "required": [
                    "endpoint",
                    "secret"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        }
      ],
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "getWebhookEndpoint",
        "summary": "List endpoints and last 30 deliveries",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "No signing secrets are returned.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    },
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "available": {
                      "type": "boolean"
                    },
                    "eventTypes": {
                      "type": "array",
                      "items": {
                        "type": "string",
                        "enum": [
                          "invoice.created",
                          "invoice.updated",
                          "payment.succeeded",
                          "payment.failed",
                          "payment.refunded",
                          "payment.partially_refunded",
                          "payment.disputed",
                          "payment.review_required"
                        ]
                      }
                    }
                  },
                  "required": [
                    "endpoints",
                    "deliveries",
                    "available",
                    "eventTypes"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "setWebhookStatus",
        "summary": "Pause or resume a verified endpoint",
        "description": "Paused verified endpoints keep eligible events in the queue; resuming processes due deliveries.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "paused"
                    ]
                  }
                },
                "required": [
                  "status"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status saved.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "updated": {
                      "const": true
                    }
                  },
                  "required": [
                    "updated"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "deleteWebhookEndpoint",
        "summary": "Remove endpoint and cancel undelivered jobs",
        "description": "Cancels pending, failed and leased jobs. A request already sent across the network cannot be recalled.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint removed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "const": true
                    }
                  },
                  "required": [
                    "deleted"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}/verify": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "verifyWebhookEndpoint",
        "summary": "Send a signed endpoint.verification challenge",
        "description": "Maximum 5 verification attempts/hour/user. Your server must validate Kevmi-Signature and return 2xx JSON {\"challenge\":\"<data.challenge>\"}. Request timeout: 8 seconds; response cap: 8192 bytes. Redirects are not followed. Verification activates the endpoint.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verified and active.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "const": true
                    },
                    "endpoint": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    }
                  },
                  "required": [
                    "verified",
                    "endpoint"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "422": {
            "description": "Destination could not be verified.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "WEBHOOK_UNREACHABLE",
              "WEBHOOK_VERIFICATION_FAILED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}/rotate": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "rotateWebhookSecret",
        "summary": "Replace signing secret and require verification again",
        "description": "Maximum 3 rotations/hour/user. Update your server and verify the endpoint again. An already in-flight request may still carry the previous signature.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New secret shown once.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string",
                      "pattern": "^whsec_[A-Za-z0-9_-]{43}$",
                      "description": "Shown only on create/rotate. Stored encrypted server-side."
                    },
                    "requiresVerification": {
                      "const": true
                    }
                  },
                  "required": [
                    "secret",
                    "requiresVerification"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/webhooks/{id}/deliveries/{deliveryId}/retry": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          }
        },
        {
          "name": "deliveryId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^del_[a-f0-9]{40}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "retryWebhookDelivery",
        "summary": "Retry a failed delivery to an active endpoint",
        "description": "Retains event ID and payload; generates a fresh timestamp and signature. Each automatic delivery cycle makes at most 6 attempts, including expired leases, with delays of 1m, 5m, 30m, 2h and 12h. Delivery is at least once; deduplicate event IDs on your server.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Retry scheduled.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "queued": {
                      "const": true
                    }
                  },
                  "required": [
                    "queued"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/applications": {
      "get": {
        "tags": [
          "Applications"
        ],
        "operationId": "listOwnApplications",
        "summary": "List up to 30 own applications",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "responses": {
          "200": {
            "description": "Newest first.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "applications": {
                      "type": "array",
                      "maxItems": 30,
                      "items": {
                        "$ref": "#/components/schemas/Application"
                      }
                    }
                  },
                  "required": [
                    "applications"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      },
      "post": {
        "tags": [
          "Applications"
        ],
        "operationId": "submitWebsiteApplication",
        "summary": "Submit website information and receive a tracking URL",
        "description": "Requires confirmed Telegram sign-in. Up to 5 new submissions/day/user. Idempotent replay returns 200. The server advances real persisted stages; unavailable or risky automatic results require human review. Approval does not configure the payment gateway. Ownership and state cannot be supplied by the applicant.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,100}$"
            },
            "description": "One key per logical request. A repeat with identical canonical input returns the original record; different input with the same key returns 409."
          },
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "websiteUrl": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048,
                    "description": "Public HTTPS domain without credentials, query parameters, IP literals or custom ports. A fragment is removed during normalization."
                  },
                  "businessName": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  },
                  "businessType": {
                    "type": "string",
                    "enum": [
                      "digital_goods",
                      "software",
                      "services",
                      "physical_goods",
                      "education",
                      "other"
                    ]
                  },
                  "description": {
                    "type": "string",
                    "minLength": 40,
                    "maxLength": 3000
                  },
                  "contactTelegram": {
                    "type": "string",
                    "description": "A 5–32 character Telegram username beginning with a letter, then letters/digits/underscores. Optional @ or https://t.me/ prefix; surrounding whitespace is trimmed. Stored as @username."
                  },
                  "consent": {
                    "type": "boolean",
                    "const": true
                  }
                },
                "required": [
                  "websiteUrl",
                  "businessName",
                  "businessType",
                  "description",
                  "contactTelegram",
                  "consent"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing submission.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "application",
                    "url",
                    "replayed"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "202": {
            "description": "Accepted; processing continues on the server.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "application",
                    "url",
                    "replayed"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/applications/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "get": {
        "tags": [
          "Applications"
        ],
        "operationId": "getOwnApplication",
        "summary": "Read own review stages and event history",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "parameters": [
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "responses": {
          "200": {
            "description": "Private applicant projection. Evidence and model output are not exposed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "events": {
                      "type": "array",
                      "maxItems": 40,
                      "items": {
                        "$ref": "#/components/schemas/ApplicationEvent"
                      }
                    }
                  },
                  "required": [
                    "application",
                    "events"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/applications/{id}/resume": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Applications"
        ],
        "operationId": "resumeApplicationJob",
        "summary": "Resume an eligible background stage",
        "description": "Cannot skip review or approve a stage. A server lease prevents duplicate work. Needs-review and final applications remain unchanged. At most 30 processing-resume requests/minute/user.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "X-Kevmi-Locale",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en",
                "es",
                "de",
                "fr"
              ]
            },
            "description": "Tracking URL and system-message language. Without a supported value, same-origin referrer and browser language are considered; fallback is English."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "No processing needed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    }
                  },
                  "required": [
                    "application"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "202": {
            "description": "Processing scheduled.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "scheduled": {
                      "type": "boolean",
                      "const": true
                    }
                  },
                  "required": [
                    "application",
                    "scheduled"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/moderation/applications": {
      "get": {
        "tags": [
          "Moderation"
        ],
        "operationId": "listModerationApplications",
        "summary": "List up to 100 applications for moderation",
        "description": "Requires the authenticated Telegram identity to be in MODERATOR_TELEGRAM_IDS. Includes all states, ordered needs_review first, processing second, then final states; newest updates first within a group.",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Moderator queue.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "applications": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/Application"
                      }
                    }
                  },
                  "required": [
                    "applications"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/moderation/applications/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "get": {
        "tags": [
          "Moderation"
        ],
        "operationId": "getModerationApplication",
        "summary": "Read review evidence and stage history",
        "security": [
          {
            "cookieSession": []
          }
        ],
        "responses": {
          "200": {
            "description": "Private moderator evidence.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    },
                    "events": {
                      "type": "array",
                      "maxItems": 40,
                      "items": {
                        "$ref": "#/components/schemas/ApplicationEvent"
                      }
                    },
                    "evidence": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "application",
                    "events",
                    "evidence"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/moderation/applications/{id}/decision": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          }
        }
      ],
      "post": {
        "tags": [
          "Moderation"
        ],
        "operationId": "decideApplicationStage",
        "summary": "Approve the current review stage or decline with a public reason",
        "description": "Requires a configured moderator; at most 30 decisions/minute/user. expectedVersion is compared atomically. Only the current needs_review stage can be approved; final applications cannot be silently reopened. A rejection requires an editable public reason. The decision, stage history and enabled applicant notification are saved together.",
        "security": [
          {
            "cookieSession": [],
            "csrfToken": []
          }
        ],
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "X-CSRF-Token",
            "in": "header",
            "required": true,
            "description": "Current session token from GET /api/auth/me or successful sign-in completion.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "properties": {
                      "expectedVersion": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "action": {
                        "type": "string",
                        "const": "approve_step"
                      },
                      "reason": {
                        "type": "string",
                        "maxLength": 0
                      }
                    },
                    "required": [
                      "expectedVersion",
                      "action"
                    ],
                    "additionalProperties": false
                  },
                  {
                    "type": "object",
                    "properties": {
                      "expectedVersion": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "action": {
                        "type": "string",
                        "const": "reject"
                      },
                      "reason": {
                        "type": "string",
                        "minLength": 10,
                        "maxLength": 1500
                      }
                    },
                    "required": [
                      "expectedVersion",
                      "action",
                      "reason"
                    ],
                    "additionalProperties": false
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Decision saved.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "application": {
                      "$ref": "#/components/schemas/Application"
                    }
                  },
                  "required": [
                    "application"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/gateway/webhook": {
      "post": {
        "tags": [
          "Gateway events"
        ],
        "operationId": "receiveGatewayEvent",
        "summary": "Receive signed source-native gateway events",
        "description": "Native v3: supply X-Gateway-Timestamp (Unix seconds), X-Gateway-Signature and matching X-Gateway-Event-Id. Maximum timestamp skew is 300 seconds. After signature verification, Kevmi fetches the payment through the authenticated gateway API, checks saved order, exact currency/amount, method and provider-confirmed state, then atomically stores the receipt and merchant outbox event. Webhook text and browser observations alone never confirm a payment. Repeated IDs are deduplicated; a changed body for an existing ID is rejected. Delayed events use fresh authoritative state. Partial refunds, full refunds, disputes and review states are supported. Unbound orders are acknowledged and ignored. Legacy normalized events using Kevmi-Signature remain supported separately; only their succeeded/failed/full-refunded transitions apply.",
        "security": [
          {
            "nativeGatewaySignature": []
          },
          {
            "gatewaySignature": []
          }
        ],
        "parameters": [
          {
            "name": "X-Gateway-Timestamp",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{10}$"
            },
            "description": "Required for native v3 events."
          },
          {
            "name": "X-Gateway-Event-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Required for native v3; must match body.id."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Exact signed JSON body; native v3 limit: 524288 bytes. Do not parse and reserialize before signature verification.",
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/NativeGatewayEvent"
                  },
                  {
                    "$ref": "#/components/schemas/LegacyGatewayEvent"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Received, deduplicated, or safely ignored.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "received": {
                      "type": "boolean",
                      "const": true
                    },
                    "replayed": {
                      "type": "boolean"
                    },
                    "ignored": {
                      "type": "boolean"
                    },
                    "applied": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "received"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "401": {
            "description": "The gateway signature is missing, invalid or outside the accepted time window.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_GATEWAY_SIGNATURE",
              "INVALID_SIGNATURE",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "An event ID was reused with changed content or a payment ID conflicts with the saved invoice binding.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_EVENT_CONFLICT",
              "PAYMENT_ID_CONFLICT"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "The gateway is busy; retry webhook delivery with the same event ID.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_BUSY"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "The gateway configuration or signing secret is missing.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_NOT_CONNECTED",
              "DATABASE_NOT_CONFIGURED"
            ]
          }
        }
      }
    },
    "/api/jobs/dispatch": {
      "post": {
        "tags": [
          "Service"
        ],
        "operationId": "dispatchBackgroundJobs",
        "summary": "Run due delivery and application jobs",
        "description": "Server scheduler entrypoint. Requires JOBS_SECRET, not a browser session or merchant key. Does not accept job IDs or arbitrary outbound URLs.",
        "security": [
          {
            "jobSecret": []
          }
        ],
        "responses": {
          "200": {
            "description": "Completed without a background context.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "202": {
            "description": "Accepted in a background execution context.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accepted": {
                      "const": true
                    }
                  },
                  "required": [
                    "accepted"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "No valid session; for a webhook, an invalid secret.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "AUTH_REQUIRED",
              "SESSION_EXPIRED",
              "WEBHOOK_UNAUTHORIZED"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/status": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Random public identifier from the checkout URL. Grants read access to this invoice only."
        }
      ],
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getCheckoutPaymentStatus",
        "summary": "Read and refresh the same payment",
        "description": "No account is required. Refreshes an existing operation over authenticated gateway transport, with server-side throttling. No new payment is created. Returns null if nothing was dispatched. Confirm an order only when fulfillmentReady is true.",
        "responses": {
          "200": {
            "description": "Current sanitized payment state.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/reconcile": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Random public identifier from the checkout URL. Grants read access to this invoice only."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "reconcileCheckoutPayment",
        "summary": "Request an authoritative status reconciliation",
        "description": "Reads the existing operation and asks the gateway to reconcile its provider status. Does not create a payment. At most 3 requests per invoice per minute. Available for already-dispatched payments even if the invoice is no longer active.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmptyObject"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reconciled payment or null.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/card-intent": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Random public identifier from the checkout URL. Grants read access to this invoice only."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "createCardEncryptionIntent",
        "summary": "Obtain a gateway public key and a bound encryption intent",
        "description": "The gateway alone owns the private key. An intent expires within five minutes and binds the merchant order, currency, base/total amounts, operation idempotency key and purpose. payment intents require an active invoice and approved merchant; code intents require an existing, current bank challenge. No PAN, CVV, bank code, or private JWK fields are accepted by this endpoint. At most 8 intents per invoice and 12 per client per minute. The encrypted plaintext is {intent,name,country,email?,card:{number,expiration,cvv,holder}} for payment or {intent,code} for code. Plaintext is assembled only inside the browser before JWE encryption.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object, at most 2048 bytes.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "purpose": {
                    "type": "string",
                    "enum": [
                      "payment",
                      "code"
                    ],
                    "default": "payment"
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Short-lived intent and public RSA key only.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardIntent"
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/code": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Random public identifier from the checkout URL. Grants read access to this invoice only."
        }
      ],
      "post": {
        "tags": [
          "Checkout"
        ],
        "operationId": "submitEncryptedBankCode",
        "summary": "Relay an encrypted code for the current bank challenge",
        "description": "Obtain a purpose=code intent and encrypt {intent,code} in the browser. The gateway validates the current challenge and consumes the sealed intent once. Kevmi never receives plaintext code. At most 5 submissions per invoice per minute; refresh status after an uncertain response.",
        "parameters": [
          {
            "name": "Origin",
            "in": "header",
            "required": true,
            "description": "Must exactly match APP_ORIGIN. Sec-Fetch-Site: cross-site is rejected. The server does not provide CORS access.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sealed": {
                    "$ref": "#/components/schemas/SealedCardData"
                  }
                },
                "required": [
                  "sealed"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Code sent; current payment state.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/CheckoutPayment"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "replayed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "payment"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "403": {
            "description": "Origin, CSRF or browser-binding validation failed.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_ORIGIN",
              "CSRF_REQUIRED",
              "BROWSER_PROOF_REQUIRED",
              "INVALID_CHALLENGE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "409": {
            "description": "The sign-in request is used or cancelled, identity is not confirmed, or a support request conflicts.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CHALLENGE_UNAVAILABLE",
              "IDENTITY_INCOMPLETE",
              "TICKET_CONFLICT",
              "IDEMPOTENCY_CONFLICT",
              "LINK_CANCELLED",
              "LINK_EXPIRED",
              "LINK_UNAVAILABLE"
            ]
          },
          "410": {
            "description": "The gateway encryption intent or bank challenge expired. Obtain a fresh intent for the same operation; do not create a replacement payment.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "CARD_SESSION_INVALID"
            ]
          },
          "413": {
            "description": "Body exceeds 16,384 bytes; the limit is 65,536 bytes for /api/support/ask and the Telegram webhook.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "REQUEST_TOO_LARGE"
            ]
          },
          "415": {
            "description": "Content-Type: application/json is required.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "JSON_REQUIRED"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    },
    "/api/checkout/{token}/crypto-services": {
      "parameters": [
        {
          "name": "token",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "description": "Random public identifier from the checkout URL. Grants read access to this invoice only."
        }
      ],
      "get": {
        "tags": [
          "Checkout"
        ],
        "operationId": "getCheckoutCryptoServices",
        "summary": "Read the current coin and network catalog",
        "description": "Only for a USDT invoice that allows crypto. The invoice remains denominated in USDT; the gateway quotes the chosen payer coin. Never assume USD equals USDT or convert the transfer amount to a floating-point number. At most 10 catalog reads per invoice per minute.",
        "responses": {
          "200": {
            "description": "Gateway-provided catalog, with current availability and transfer limits.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "services": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "currency": {
                            "type": "string"
                          },
                          "network": {
                            "type": "string"
                          },
                          "networkLabel": {
                            "type": "string"
                          },
                          "available": {
                            "type": "boolean"
                          },
                          "minAmount": {
                            "type": "string",
                            "pattern": "^[0-9]+(?:\\.[0-9]+)?$",
                            "description": "Exact decimal value in the selected transfer coin."
                          },
                          "maxAmount": {
                            "type": "string",
                            "pattern": "^[0-9]+(?:\\.[0-9]+)?$",
                            "description": "Exact decimal value in the selected transfer coin."
                          },
                          "confirmations": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "minimum": 0
                          }
                        },
                        "required": [
                          "currency",
                          "network",
                          "networkLabel",
                          "available",
                          "minAmount",
                          "maxAmount",
                          "confirmations"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "fetchedAt": {
                      "type": "integer",
                      "minimum": 0,
                      "description": "Unix timestamp in milliseconds, UTC."
                    }
                  },
                  "required": [
                    "services",
                    "fetchedAt"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, unknown field or invalid value.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "INVALID_JSON",
              "UNKNOWN_FIELD",
              "INVALID_INPUT",
              "INVALID_VAT_PAYER",
              "INVALID_NOTIFICATIONS",
              "INVALID_TICKET_STATUS",
              "INVALID_UPDATE",
              "INVALID_HISTORY",
              "INVALID_PAGE_CONTEXT",
              "INVALID_LOCALE",
              "INVALID_FILTER",
              "INVALID_NOTIFICATION_SELECTION",
              "INVALID_AMOUNT",
              "INVALID_CURRENCY",
              "INVALID_METHODS",
              "INVALID_EXPIRY",
              "INVALID_QUOTE",
              "INVALID_LIMIT",
              "INVALID_CURSOR",
              "INVALID_STATUS",
              "IDEMPOTENCY_KEY_REQUIRED",
              "METHOD_UNAVAILABLE"
            ]
          },
          "404": {
            "description": "The record is missing, the public token is invalid, or the requested record belongs to another user.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "TICKET_NOT_FOUND",
              "LINK_NOT_FOUND"
            ]
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "string",
                  "const": "60"
                },
                "description": "The server always returns 60; this does not guarantee that an hourly quota has expired."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "RATE_LIMITED"
            ]
          },
          "502": {
            "description": "Gateway response unavailable, malformed, or not verifiable. Read the existing payment status before attempting any retry.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "GATEWAY_REQUEST_UNCERTAIN",
              "GATEWAY_INVALID_RESPONSE"
            ]
          },
          "503": {
            "description": "An integration or storage is unavailable, an event is being processed, or the service is unavailable.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "x-error-codes": [
              "DATABASE_NOT_CONFIGURED",
              "ORIGIN_NOT_CONFIGURED",
              "TELEGRAM_NOT_CONFIGURED",
              "UPDATE_IN_PROGRESS",
              "SERVICE_UNAVAILABLE",
              "GATEWAY_NOT_CONNECTED"
            ]
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "cookieSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-kevmi-session",
        "description": "Random session token, Secure/HttpOnly/SameSite=Lax, valid for 24 hours. A hash is stored in the database. Issued only after verified Telegram sign-in."
      },
      "browserProof": {
        "type": "apiKey",
        "in": "cookie",
        "name": "__Host-kevmi-login",
        "description": "HttpOnly cookie from start: challengeId.proof, valid for 300 seconds. Excluded from the Telegram deep link."
      },
      "csrfToken": {
        "type": "apiKey",
        "in": "header",
        "name": "X-CSRF-Token",
        "description": "Session CSRF token issued by /api/auth/me or /api/auth/telegram/complete. Mutations also require the exact Origin."
      },
      "telegramWebhookSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Telegram-Bot-Api-Secret-Token",
        "description": "Separate server-configured webhook secret. Its value is private. This is not the bot token."
      },
      "merchantKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "kv_live_…",
        "description": "Scoped merchant API key. Only its hash is stored. Server-to-server use only; never place it in a widget or browser bundle."
      },
      "gatewaySignature": {
        "type": "apiKey",
        "in": "header",
        "name": "Kevmi-Signature",
        "description": "t=<Unix seconds>,v1=<hex HMAC-SHA256(secret, timestamp + dot + exact UTF-8 request body)>. Maximum timestamp skew: 300 seconds."
      },
      "jobSecret": {
        "type": "http",
        "scheme": "bearer",
        "description": "Separate server-only JOBS_SECRET. Not a merchant API key."
      },
      "nativeGatewaySignature": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Gateway-Signature",
        "description": "v1=<hex HMAC-SHA256(GATEWAY_WEBHOOK_SECRET, timestamp + \".\" + exact raw UTF-8 body)>; separate from merchant Kevmi-Signature."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": false
      },
      "EmptyObject": {
        "type": "object",
        "properties": {},
        "required": [],
        "additionalProperties": false
      },
      "Config": {
        "type": "object",
        "properties": {
          "telegram": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "botUsername": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "enabled",
              "botUsername"
            ],
            "additionalProperties": false
          },
          "support": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "search",
                  "ai"
                ]
              },
              "available": {
                "type": "boolean",
                "const": true
              }
            },
            "required": [
              "mode",
              "available"
            ],
            "additionalProperties": false
          },
          "gateway": {
            "type": "object",
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "connected": {
                "type": "boolean",
                "const": false,
                "description": "The public configuration endpoint does not probe gateway health. Configuration is not a successful live connection check."
              },
              "status": {
                "type": "string",
                "enum": [
                  "configured",
                  "not_configured"
                ]
              }
            },
            "required": [
              "configured",
              "connected",
              "status"
            ],
            "additionalProperties": false
          },
          "capabilities": {
            "type": "object",
            "properties": {
              "server": {
                "type": "boolean",
                "const": true
              },
              "account": {
                "type": "boolean"
              },
              "notifications": {
                "type": "boolean"
              },
              "tickets": {
                "type": "boolean"
              },
              "directPaymentsOnly": {
                "type": "boolean",
                "const": true
              },
              "paymentLinks": {
                "type": "boolean",
                "description": "D1 is configured for server invoices. This does not indicate payment readiness."
              },
              "apiKeys": {
                "type": "boolean"
              },
              "webhooks": {
                "type": "boolean"
              },
              "widgets": {
                "type": "boolean"
              },
              "applications": {
                "type": "boolean"
              },
              "applicationNotifications": {
                "type": "boolean"
              }
            },
            "required": [
              "server",
              "account",
              "notifications",
              "tickets",
              "directPaymentsOnly",
              "paymentLinks",
              "apiKeys",
              "webhooks",
              "widgets",
              "applications",
              "applicationNotifications"
            ],
            "additionalProperties": false
          }
        },
        "required": [
          "telegram",
          "support",
          "gateway",
          "capabilities"
        ],
        "additionalProperties": false
      },
      "Health": {
        "type": "object",
        "properties": {
          "telegram": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "botUsername": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "enabled",
              "botUsername"
            ],
            "additionalProperties": false
          },
          "support": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "search",
                  "ai"
                ]
              },
              "available": {
                "type": "boolean",
                "const": true
              }
            },
            "required": [
              "mode",
              "available"
            ],
            "additionalProperties": false
          },
          "gateway": {
            "type": "object",
            "properties": {
              "configured": {
                "type": "boolean"
              },
              "connected": {
                "type": "boolean",
                "const": false,
                "description": "The public configuration endpoint does not probe gateway health. Configuration is not a successful live connection check."
              },
              "status": {
                "type": "string",
                "enum": [
                  "configured",
                  "not_configured"
                ]
              }
            },
            "required": [
              "configured",
              "connected",
              "status"
            ],
            "additionalProperties": false
          },
          "capabilities": {
            "type": "object",
            "properties": {
              "server": {
                "type": "boolean",
                "const": true
              },
              "account": {
                "type": "boolean"
              },
              "notifications": {
                "type": "boolean"
              },
              "tickets": {
                "type": "boolean"
              },
              "directPaymentsOnly": {
                "type": "boolean",
                "const": true
              },
              "paymentLinks": {
                "type": "boolean",
                "description": "D1 is configured for server invoices. This does not indicate payment readiness."
              },
              "apiKeys": {
                "type": "boolean"
              },
              "webhooks": {
                "type": "boolean"
              },
              "widgets": {
                "type": "boolean"
              },
              "applications": {
                "type": "boolean"
              },
              "applicationNotifications": {
                "type": "boolean"
              }
            },
            "required": [
              "server",
              "account",
              "notifications",
              "tickets",
              "directPaymentsOnly",
              "paymentLinks",
              "apiKeys",
              "webhooks",
              "widgets",
              "applications",
              "applicationNotifications"
            ],
            "additionalProperties": false
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "degraded"
            ]
          },
          "storage": {
            "type": "string",
            "enum": [
              "ready",
              "not_configured",
              "unavailable"
            ]
          }
        },
        "required": [
          "telegram",
          "support",
          "gateway",
          "capabilities",
          "status",
          "storage"
        ],
        "additionalProperties": false
      },
      "NotificationPreferences": {
        "type": "object",
        "properties": {
          "payments": {
            "type": "boolean"
          },
          "payouts": {
            "type": "boolean"
          },
          "support": {
            "type": "boolean"
          },
          "security": {
            "type": "boolean"
          }
        },
        "required": [
          "payments",
          "payouts",
          "support",
          "security"
        ],
        "additionalProperties": false
      },
      "SettingsPatch": {
        "type": "object",
        "properties": {
          "storeName": {
            "type": "string",
            "minLength": 1,
            "x-trimmedMaxLength": 80,
            "x-trimmedMinLength": 1,
            "description": "Surrounding spaces are trimmed. Length after trim: 1–80 characters. Control characters except tabs and line breaks are forbidden."
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant"
            ]
          },
          "notifications": {
            "type": "object",
            "properties": {
              "payments": {
                "type": "boolean"
              },
              "payouts": {
                "type": "boolean"
              },
              "support": {
                "type": "boolean"
              },
              "security": {
                "type": "boolean"
              }
            },
            "required": [],
            "additionalProperties": false
          }
        },
        "required": [],
        "additionalProperties": false
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "username": {
            "type": [
              "string",
              "null"
            ]
          },
          "storeName": {
            "type": "string"
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant"
            ]
          },
          "notifications": {
            "$ref": "#/components/schemas/NotificationPreferences"
          },
          "isModerator": {
            "type": "boolean",
            "description": "Whether this Telegram identity belongs to the configured moderator allowlist."
          }
        },
        "required": [
          "id",
          "displayName",
          "username",
          "storeName",
          "vatPayer",
          "notifications",
          "isModerator"
        ],
        "additionalProperties": false
      },
      "UserResponse": {
        "type": "object",
        "properties": {
          "user": {
            "$ref": "#/components/schemas/User"
          }
        },
        "required": [
          "user"
        ],
        "additionalProperties": false
      },
      "Anonymous": {
        "type": "object",
        "properties": {
          "authenticated": {
            "type": "boolean",
            "const": false
          }
        },
        "required": [
          "authenticated"
        ],
        "additionalProperties": false
      },
      "CurrentSession": {
        "type": "object",
        "properties": {
          "authenticated": {
            "type": "boolean",
            "const": true
          },
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "csrfToken": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "authenticated",
          "user",
          "csrfToken",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "LoginChallenge": {
        "type": "object",
        "properties": {
          "challengeId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "code": {
            "type": "string",
            "pattern": "^[0-9]{6}$"
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "telegramUrl": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://t\\.me/"
          }
        },
        "required": [
          "challengeId",
          "code",
          "expiresAt",
          "telegramUrl"
        ],
        "additionalProperties": false
      },
      "CompletedLogin": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "const": "authenticated"
          },
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "csrfToken": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "status",
          "user",
          "csrfToken",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "SupportQuestion": {
        "type": "object",
        "properties": {
          "question": {
            "type": "string",
            "minLength": 2,
            "x-trimmedMaxLength": 2000,
            "x-trimmedMinLength": 2,
            "description": "Surrounding spaces are trimmed. Length after trim: 2–2,000 characters. Control characters except tabs and line breaks are forbidden."
          },
          "locale": {
            "type": "string",
            "enum": [
              "ru",
              "en",
              "es",
              "de",
              "fr"
            ],
            "default": "en",
            "description": "Response language. If omitted, supported Accept-Language preferences are used; otherwise English. Articles for ES/DE/FR currently link to the English documentation edition."
          },
          "history": {
            "type": "array",
            "maxItems": 6,
            "description": "Up to the latest three question-and-answer pairs. Optional. Untrusted context, not provider system-role messages.",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string",
                      "const": "user"
                    },
                    "content": {
                      "type": "string",
                      "minLength": 1,
                      "x-trimmedMaxLength": 1800,
                      "x-trimmedMinLength": 1,
                      "description": "Surrounding spaces are trimmed. Length after trim: 1–1,800 characters. Control characters except tabs and line breaks are forbidden."
                    }
                  },
                  "required": [
                    "role",
                    "content"
                  ],
                  "additionalProperties": false
                },
                {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string",
                      "const": "assistant"
                    },
                    "content": {
                      "type": "string",
                      "minLength": 1,
                      "x-trimmedMaxLength": 3000,
                      "x-trimmedMinLength": 1,
                      "description": "Surrounding spaces are trimmed. Length after trim: 1–3,000 characters. Control characters except tabs and line breaks are forbidden."
                    }
                  },
                  "required": [
                    "role",
                    "content"
                  ],
                  "additionalProperties": false
                }
              ]
            }
          },
          "pageContext": {
            "type": "string",
            "minLength": 1,
            "x-trimmedMaxLength": 80,
            "x-trimmedMinLength": 1,
            "description": "Short section label after trim, 1–80 characters. Allows letters, digits, spaces and ·.,—–-:(). Line breaks, URLs, query parameters and HTML are forbidden. Do not include tokens or secrets.",
            "pattern": "^[\\p{L}\\p{N}\\s·.,—–\\-:()]+$",
            "not": {
              "pattern": "[\\r\\n]"
            }
          }
        },
        "required": [
          "question"
        ],
        "additionalProperties": false
      },
      "SupportSource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "pattern": "^/(?:ru/|en/)?docs/[^/]+$",
            "description": "Relative link to a published knowledge article."
          }
        },
        "required": [
          "id",
          "title",
          "url"
        ],
        "additionalProperties": false
      },
      "SearchSupportAnswer": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "const": "search"
          },
          "answer": {
            "type": "string"
          },
          "sources": {
            "type": "array",
            "maxItems": 3,
            "items": {
              "$ref": "#/components/schemas/SupportSource"
            }
          },
          "knowledgeVersion": {
            "type": [
              "string",
              "null"
            ]
          },
          "needsHuman": {
            "type": "boolean"
          },
          "aiUnavailable": {
            "type": "boolean",
            "const": true
          }
        },
        "required": [
          "mode",
          "answer",
          "sources",
          "knowledgeVersion",
          "needsHuman"
        ],
        "additionalProperties": false
      },
      "AISupportAnswer": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "const": "ai"
          },
          "answer": {
            "type": "string",
            "minLength": 1,
            "maxLength": 6000,
            "description": "Plain text only; URLs and HTML are rejected. Links are returned only in sources."
          },
          "sources": {
            "type": "array",
            "maxItems": 25,
            "uniqueItems": true,
            "items": {
              "$ref": "#/components/schemas/SupportSource"
            }
          },
          "knowledgeVersion": {
            "type": "string"
          },
          "needsHuman": {
            "type": "boolean"
          }
        },
        "required": [
          "mode",
          "answer",
          "sources",
          "knowledgeVersion",
          "needsHuman"
        ],
        "additionalProperties": false,
        "allOf": [
          {
            "if": {
              "properties": {
                "needsHuman": {
                  "const": false
                }
              }
            },
            "then": {
              "properties": {
                "sources": {
                  "minItems": 1
                }
              }
            }
          }
        ]
      },
      "SupportAnswer": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/SearchSupportAnswer"
          },
          {
            "$ref": "#/components/schemas/AISupportAnswer"
          }
        ]
      },
      "Ticket": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^tkt_[a-f0-9-]{36}$"
          },
          "subject": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "answered",
              "closed"
            ],
            "description": "answered denotes an answered request. The public API lets a user close only their own request."
          },
          "source": {
            "type": "string",
            "enum": [
              "web",
              "telegram"
            ]
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "id",
          "subject",
          "message",
          "status",
          "source",
          "createdAt",
          "updatedAt"
        ],
        "additionalProperties": false
      },
      "TicketResponse": {
        "type": "object",
        "properties": {
          "ticket": {
            "$ref": "#/components/schemas/Ticket"
          }
        },
        "required": [
          "ticket"
        ],
        "additionalProperties": false
      },
      "Notification": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^ntf_[A-Za-z0-9-]{1,80}$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "payments",
              "payouts",
              "support",
              "security",
              "test"
            ]
          },
          "message": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "sending",
              "sent",
              "failed"
            ],
            "description": "Telegram delivery state, independent of website read state."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "sentAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "readAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Time first read on the website; null means unread. This does not confirm that it was read in Telegram."
          }
        },
        "required": [
          "id",
          "kind",
          "message",
          "status",
          "createdAt",
          "sentAt",
          "readAt"
        ],
        "additionalProperties": false
      },
      "NotificationsPage": {
        "type": "object",
        "properties": {
          "notifications": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "$ref": "#/components/schemas/Notification"
            }
          },
          "unreadCount": {
            "type": "integer",
            "minimum": 0
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Next-page cursor; null if no further records remain."
          }
        },
        "required": [
          "notifications",
          "unreadCount",
          "nextCursor"
        ],
        "additionalProperties": false
      },
      "ReadNotifications": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "ids": {
                "type": "array",
                "minItems": 1,
                "maxItems": 100,
                "description": "Duplicates are allowed and counted once.",
                "items": {
                  "type": "string",
                  "pattern": "^ntf_[A-Za-z0-9-]{1,80}$"
                }
              }
            },
            "required": [
              "ids"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "all": {
                "type": "boolean",
                "const": true
              },
              "before": {
                "type": "integer",
                "minimum": 0,
                "description": "createdAt of the last displayed event. The server also requires before <= Date.now().",
                "maximum": 9007199254740991
              }
            },
            "required": [
              "all",
              "before"
            ],
            "additionalProperties": false
          }
        ]
      },
      "ReadNotificationsResult": {
        "type": "object",
        "properties": {
          "updated": {
            "type": "integer",
            "minimum": 0
          },
          "readAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "unreadCount": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "updated",
          "readAt",
          "unreadCount"
        ],
        "additionalProperties": false
      },
      "TelegramUpdate": {
        "type": "object",
        "properties": {
          "update_id": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "message": {
            "type": "object",
            "additionalProperties": true,
            "description": "Telegram Message: the handler uses message_id, text, from and chat."
          },
          "callback_query": {
            "type": "object",
            "additionalProperties": true,
            "description": "Telegram CallbackQuery: the handler uses id, from, data and message.chat."
          }
        },
        "required": [
          "update_id"
        ],
        "additionalProperties": true
      },
      "IncomingQuote": {
        "type": "object",
        "properties": {
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "baseMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "grossMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "percentageFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "fixedFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "nominalFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "feeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "vatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "customerVatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "merchantVatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "customerTotalMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "merchantDeductionMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "totalFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "netMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant",
              "shared"
            ]
          },
          "vatApplies": {
            "type": "boolean"
          },
          "pricingVersion": {
            "type": "integer",
            "minimum": 1,
            "description": "Calculation version saved with the invoice."
          },
          "vatCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
          },
          "feeCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
            "default": 0
          },
          "customerFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "merchantFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          }
        },
        "required": [
          "amountMinor",
          "baseMinor",
          "grossMinor",
          "percentageFeeMinor",
          "fixedFeeMinor",
          "nominalFeeMinor",
          "feeMinor",
          "vatMinor",
          "customerVatMinor",
          "merchantVatMinor",
          "customerTotalMinor",
          "merchantDeductionMinor",
          "totalFeeMinor",
          "netMinor",
          "currency",
          "method",
          "vatPayer",
          "vatApplies",
          "pricingVersion"
        ],
        "additionalProperties": false
      },
      "PaymentLink": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "merchantName": {
            "type": "string"
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant",
              "shared"
            ]
          },
          "methods": {
            "type": "array",
            "minItems": 1,
            "maxItems": 3,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "card",
                "alipay",
                "sbp",
                "crypto"
              ]
            }
          },
          "quotes": {
            "type": "object",
            "properties": {
              "card": {
                "$ref": "#/components/schemas/IncomingQuote"
              },
              "alipay": {
                "$ref": "#/components/schemas/IncomingQuote"
              },
              "sbp": {
                "$ref": "#/components/schemas/IncomingQuote"
              },
              "crypto": {
                "$ref": "#/components/schemas/IncomingQuote"
              }
            },
            "required": [],
            "additionalProperties": false
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "expired",
              "cancelled"
            ],
            "description": "expired is derived from expiresAt on read. cancelled is final."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Public /pay/{token} page on APP_ORIGIN."
          },
          "vatCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
          },
          "feeCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
            "default": 0
          },
          "orderId": {
            "type": "string",
            "maxLength": 100,
            "description": "Buyer-visible order reference."
          },
          "metadata": {
            "type": "object",
            "maxProperties": 10,
            "propertyNames": {
              "pattern": "^[A-Za-z0-9_-]{1,40}$"
            },
            "additionalProperties": {
              "type": "string",
              "maxLength": 500
            },
            "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri"
          },
          "payment": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/PaymentSummary"
              },
              {
                "type": "null"
              }
            ],
            "description": "Included by owner list/detail GET requests. The invoice lifecycle is independent of the verified payment status. Does not contain card, bank-code, QR or buyer details."
          }
        },
        "required": [
          "id",
          "title",
          "description",
          "merchantName",
          "amountMinor",
          "currency",
          "vatPayer",
          "methods",
          "quotes",
          "status",
          "createdAt",
          "updatedAt",
          "expiresAt",
          "url",
          "vatCustomerPercent",
          "feeCustomerPercent",
          "orderId",
          "metadata",
          "checkoutUrl"
        ],
        "additionalProperties": false
      },
      "CreatePaymentLink": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "x-trimmedMaxLength": 120,
                "x-trimmedMinLength": 1,
                "description": "Surrounding spaces are trimmed. Length after trim: 1–120 characters. Control characters except tabs and line breaks are forbidden."
              },
              "description": {
                "type": "string",
                "x-trimmedMaxLength": 500,
                "description": "Optional; an empty string is allowed. Up to 500 characters after trim."
              },
              "amountMinor": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000000000,
                "description": "Technical integer boundary, not a commercial provider limit. A negative merchant credit is rejected."
              },
              "vatPayer": {
                "type": "string",
                "enum": [
                  "customer",
                  "merchant"
                ],
                "description": "When omitted, the current store's rule is saved."
              },
              "expiresAt": {
                "type": "integer",
                "minimum": 0,
                "description": "A future time, at most 90 days after creation. Defaults to seven days. Saved in the invoice snapshot."
              },
              "currency": {
                "type": "string",
                "const": "USD"
              },
              "methods": {
                "type": "array",
                "minItems": 1,
                "maxItems": 3,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "enum": [
                    "card",
                    "alipay",
                    "crypto"
                  ]
                },
                "description": "New USD checkout supports card and Alipay. USD crypto invoices are accepted only for compatibility and return crypto_requires_usdt at live checkout; use USDT for crypto."
              },
              "vatCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
              },
              "feeCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
                "default": 0
              },
              "orderId": {
                "type": "string",
                "maxLength": 100,
                "description": "Buyer-visible order reference."
              },
              "metadata": {
                "type": "object",
                "maxProperties": 10,
                "propertyNames": {
                  "pattern": "^[A-Za-z0-9_-]{1,40}$"
                },
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 500
                },
                "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
              }
            },
            "required": [
              "title",
              "amountMinor",
              "currency",
              "methods"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "x-trimmedMaxLength": 120,
                "x-trimmedMinLength": 1,
                "description": "Surrounding spaces are trimmed. Length after trim: 1–120 characters. Control characters except tabs and line breaks are forbidden."
              },
              "description": {
                "type": "string",
                "x-trimmedMaxLength": 500,
                "description": "Optional; an empty string is allowed. Up to 500 characters after trim."
              },
              "amountMinor": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000000000,
                "description": "Technical integer boundary, not a commercial provider limit. A negative merchant credit is rejected."
              },
              "vatPayer": {
                "type": "string",
                "enum": [
                  "customer",
                  "merchant"
                ],
                "description": "When omitted, the current store's rule is saved."
              },
              "expiresAt": {
                "type": "integer",
                "minimum": 0,
                "description": "A future time, at most 90 days after creation. Defaults to seven days. Saved in the invoice snapshot."
              },
              "currency": {
                "type": "string",
                "const": "RUB"
              },
              "methods": {
                "type": "array",
                "minItems": 1,
                "maxItems": 1,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "const": "sbp"
                }
              },
              "vatCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
              },
              "feeCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
                "default": 0
              },
              "orderId": {
                "type": "string",
                "maxLength": 100,
                "description": "Buyer-visible order reference."
              },
              "metadata": {
                "type": "object",
                "maxProperties": 10,
                "propertyNames": {
                  "pattern": "^[A-Za-z0-9_-]{1,40}$"
                },
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 500
                },
                "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
              }
            },
            "required": [
              "title",
              "amountMinor",
              "currency",
              "methods"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "x-trimmedMaxLength": 120,
                "x-trimmedMinLength": 1,
                "description": "Surrounding spaces are trimmed. Length after trim: 1–120 characters. Control characters except tabs and line breaks are forbidden."
              },
              "description": {
                "type": "string",
                "x-trimmedMaxLength": 500,
                "description": "Optional; an empty string is allowed. Up to 500 characters after trim."
              },
              "amountMinor": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10000000000,
                "description": "Technical integer boundary, not a commercial provider limit. A negative merchant credit is rejected."
              },
              "vatPayer": {
                "type": "string",
                "enum": [
                  "customer",
                  "merchant"
                ],
                "description": "When omitted, the current store's rule is saved."
              },
              "expiresAt": {
                "type": "integer",
                "minimum": 0,
                "description": "A future time, at most 90 days after creation. Defaults to seven days. Saved in the invoice snapshot."
              },
              "currency": {
                "type": "string",
                "const": "USDT"
              },
              "methods": {
                "type": "array",
                "minItems": 1,
                "maxItems": 1,
                "uniqueItems": true,
                "items": {
                  "type": "string",
                  "const": "crypto"
                }
              },
              "vatCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
              },
              "feeCustomerPercent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100,
                "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
                "default": 0
              },
              "orderId": {
                "type": "string",
                "maxLength": 100,
                "description": "Buyer-visible order reference."
              },
              "metadata": {
                "type": "object",
                "maxProperties": 10,
                "propertyNames": {
                  "pattern": "^[A-Za-z0-9_-]{1,40}$"
                },
                "additionalProperties": {
                  "type": "string",
                  "maxLength": 500
                },
                "description": "Private merchant metadata. At most 3000 UTF-8 bytes after JSON serialization. Never exposed in public checkout."
              }
            },
            "required": [
              "title",
              "amountMinor",
              "currency",
              "methods"
            ],
            "additionalProperties": false
          }
        ],
        "description": "Amounts use minor units. Fee and VAT are calculated on the base order amount. The customer share is rounded half-up; the merchant covers the exact remainder. A conflicting legacy vatPayer and vatCustomerPercent is rejected. Allocation is immutable after creation; issue a new invoice to change it. Live card/Alipay requires vatCustomerPercent=100 and feeCustomerPercent=0 because the configured gateway cannot override its exclusive tax. Other saved allocations return unsupported_allocation; they are never silently changed. SBP and USDT crypto support fee allocation. Use the public invoice availability object before collecting payment details.",
        "examples": [
          {
            "title": "Order 1042",
            "amountMinor": 500,
            "currency": "USD",
            "methods": [
              "card",
              "alipay"
            ],
            "vatCustomerPercent": 100,
            "feeCustomerPercent": 0,
            "orderId": "1042"
          },
          {
            "title": "Order 1043",
            "amountMinor": 1000,
            "currency": "USDT",
            "methods": [
              "crypto"
            ],
            "feeCustomerPercent": 23,
            "orderId": "1043"
          }
        ]
      },
      "PaymentLinkResponse": {
        "type": "object",
        "properties": {
          "link": {
            "$ref": "#/components/schemas/PaymentLink"
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri",
            "description": "Included in status-update responses; the nested link always contains its checkoutUrl."
          }
        },
        "required": [
          "link"
        ],
        "additionalProperties": false
      },
      "CreatePaymentLinkResponse": {
        "type": "object",
        "properties": {
          "link": {
            "$ref": "#/components/schemas/PaymentLink"
          },
          "replayed": {
            "type": "boolean"
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri",
            "description": "The payment link is available immediately; no polling is required."
          }
        },
        "required": [
          "link",
          "replayed",
          "checkoutUrl"
        ],
        "additionalProperties": false
      },
      "PaymentLinksPage": {
        "type": "object",
        "properties": {
          "links": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/PaymentLink"
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque next-page cursor. Pass as a URL-encoded query parameter; null marks the end."
          }
        },
        "required": [
          "links",
          "nextCursor"
        ],
        "additionalProperties": false
      },
      "CheckoutQuote": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "vatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "customerVatMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "customerTotalMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "vatApplies": {
            "type": "boolean"
          },
          "pricingVersion": {
            "type": "integer",
            "minimum": 1,
            "description": "Calculation version saved with the invoice."
          },
          "customerFeeMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "merchantCoveredMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          }
        },
        "required": [
          "method",
          "amountMinor",
          "vatMinor",
          "customerVatMinor",
          "customerTotalMinor",
          "vatApplies",
          "pricingVersion",
          "customerFeeMinor",
          "merchantCoveredMinor"
        ],
        "additionalProperties": false
      },
      "CheckoutInvoice": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "merchantName": {
            "type": "string"
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "vatPayer": {
            "type": "string",
            "enum": [
              "customer",
              "merchant",
              "shared"
            ]
          },
          "methods": {
            "type": "array",
            "minItems": 1,
            "maxItems": 3,
            "items": {
              "type": "string",
              "enum": [
                "card",
                "alipay",
                "sbp",
                "crypto"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "expired",
              "cancelled"
            ],
            "description": "expired is derived from expiresAt on read. cancelled is final."
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "quote": {
            "$ref": "#/components/schemas/CheckoutQuote"
          },
          "gatewayConnected": {
            "type": "boolean",
            "description": "Compatibility alias for availability.available, not a gateway health probe."
          },
          "vatCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything. Default: the store’s legacy VAT preference."
          },
          "feeCustomerPercent": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Customer share, as a whole percentage. 0 means the merchant covers everything; 100 means the customer covers everything.",
            "default": 0
          },
          "orderId": {
            "type": "string",
            "maxLength": 100,
            "description": "Buyer-visible order reference."
          },
          "availability": {
            "$ref": "#/components/schemas/CheckoutAvailability"
          }
        },
        "required": [
          "token",
          "title",
          "description",
          "merchantName",
          "amountMinor",
          "currency",
          "vatPayer",
          "methods",
          "status",
          "expiresAt",
          "createdAt",
          "quote",
          "gatewayConnected",
          "vatCustomerPercent",
          "feeCustomerPercent",
          "orderId",
          "availability"
        ],
        "additionalProperties": false
      },
      "MerchantKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^key_[0-9a-f-]{36}$"
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 3,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "invoices:read",
                "invoices:write",
                "events:read"
              ]
            }
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "revokedAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "lastUsedAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "id",
          "name",
          "prefix",
          "scopes",
          "createdAt",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "MerchantEvent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^evt_[a-f0-9]{40}$"
          },
          "type": {
            "type": "string",
            "enum": [
              "invoice.created",
              "invoice.updated",
              "payment.succeeded",
              "payment.failed",
              "payment.refunded",
              "payment.partially_refunded",
              "payment.disputed",
              "payment.review_required"
            ]
          },
          "apiVersion": {
            "type": "string",
            "const": "2026-10-21"
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "livemode": {
            "type": "boolean"
          },
          "data": {
            "type": "object",
            "additionalProperties": true,
            "description": "invoice.created/updated: persisted merchant invoice, including private metadata. payment events: verified payment facts. See the webhook guide for examples."
          }
        },
        "required": [
          "id",
          "type",
          "apiVersion",
          "createdAt",
          "livemode",
          "data"
        ],
        "additionalProperties": false
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^wh_[0-9a-f-]{36}$"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "description": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "invoice.created",
                "invoice.updated",
                "payment.succeeded",
                "payment.failed",
                "payment.refunded",
                "payment.partially_refunded",
                "payment.disputed",
                "payment.review_required"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "unverified",
              "active",
              "paused"
            ]
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "verifiedAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "id",
          "url",
          "description",
          "events",
          "status",
          "createdAt",
          "verifiedAt"
        ],
        "additionalProperties": false
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "event_id": {
            "type": "string"
          },
          "endpoint_id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "invoice.created",
              "invoice.updated",
              "payment.succeeded",
              "payment.failed",
              "payment.refunded",
              "payment.partially_refunded",
              "payment.disputed",
              "payment.review_required"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "sending",
              "delivered",
              "failed",
              "cancelled"
            ]
          },
          "attempts": {
            "type": "integer",
            "minimum": 0,
            "maximum": 6
          },
          "next_attempt_at": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "last_status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "delivered_at": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "id",
          "event_id",
          "endpoint_id",
          "type",
          "status",
          "attempts"
        ],
        "additionalProperties": false
      },
      "Application": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^app_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
          },
          "websiteUrl": {
            "type": "string",
            "format": "uri",
            "maxLength": 2048
          },
          "businessName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "businessType": {
            "type": "string",
            "enum": [
              "digital_goods",
              "software",
              "services",
              "physical_goods",
              "education",
              "other"
            ]
          },
          "description": {
            "type": "string",
            "minLength": 40,
            "maxLength": 3000
          },
          "contactTelegram": {
            "type": "string",
            "pattern": "^@[A-Za-z][A-Za-z0-9_]{4,31}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "processing",
              "needs_review",
              "approved",
              "rejected"
            ]
          },
          "currentStage": {
            "type": "string",
            "enum": [
              "received",
              "ai_review",
              "technical_review",
              "manual_review"
            ]
          },
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "reason": {
            "type": "string",
            "description": "User-facing stage message or moderator-edited decline reason. Internal evidence is excluded."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "stages": {
            "type": "array",
            "minItems": 4,
            "maxItems": 4,
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "enum": [
                    "received",
                    "ai_review",
                    "technical_review",
                    "manual_review"
                  ]
                },
                "state": {
                  "type": "string",
                  "enum": [
                    "pending",
                    "running",
                    "complete",
                    "review",
                    "rejected"
                  ]
                },
                "message": {
                  "type": "string"
                },
                "updatedAt": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "minimum": 0,
                  "description": "Unix timestamp in milliseconds, UTC."
                }
              },
              "required": [
                "id",
                "state",
                "message",
                "updatedAt"
              ],
              "additionalProperties": false
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Private, explicit-locale tracking URL. Knowing the URL does not grant access."
          },
          "notificationCategory": {
            "type": "string",
            "const": "support"
          },
          "canResume": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "websiteUrl",
          "businessName",
          "businessType",
          "description",
          "contactTelegram",
          "status",
          "currentStage",
          "version",
          "reason",
          "createdAt",
          "updatedAt",
          "stages",
          "url",
          "notificationCategory",
          "canResume"
        ],
        "additionalProperties": false
      },
      "ApplicationEvent": {
        "type": "object",
        "properties": {
          "version": {
            "type": "integer",
            "minimum": 1
          },
          "stage": {
            "type": "string",
            "enum": [
              "received",
              "ai_review",
              "technical_review",
              "manual_review"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "complete",
              "review",
              "rejected"
            ]
          },
          "message": {
            "type": "string"
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "version",
          "stage",
          "state",
          "message",
          "createdAt"
        ],
        "additionalProperties": false
      },
      "PaymentSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Canonical gateway payment ID when known; otherwise the local gwp_ operation ID."
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "requires_action",
              "processing",
              "succeeded",
              "failed",
              "expired",
              "review_required",
              "partially_paid",
              "partially_refunded",
              "refunded",
              "disputed"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "fulfillmentReady": {
            "type": "boolean"
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "refundedAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          }
        },
        "required": [
          "id",
          "method",
          "status",
          "amountMinor",
          "currency",
          "fulfillmentReady",
          "updatedAt"
        ],
        "additionalProperties": false
      },
      "CheckoutAvailability": {
        "type": "object",
        "properties": {
          "available": {
            "type": "boolean"
          },
          "code": {
            "type": "string",
            "enum": [
              "ready",
              "not_configured",
              "unsupported_allocation",
              "crypto_requires_usdt",
              "amount_out_of_range",
              "merchant_not_approved"
            ]
          },
          "flow": {
            "type": "string",
            "enum": [
              "encrypted_card",
              "qr",
              "crypto"
            ]
          },
          "minAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "maxAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "limitsSource": {
            "type": "string",
            "const": "adapter",
            "description": "Conservative limits enforced by this integration, not a claim about the upstream commercial limits."
          }
        },
        "required": [
          "available",
          "code",
          "flow",
          "minAmountMinor",
          "maxAmountMinor",
          "limitsSource"
        ],
        "additionalProperties": false
      },
      "CheckoutAction": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "redirect",
              "qr",
              "crypto"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "qrImage": {
            "type": [
              "string",
              "null"
            ]
          },
          "qrPayload": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "pattern": "^[0-9]+(?:\\.[0-9]+)?$",
            "description": "Exact transfer amount in the selected coin; preserve the decimal string without rounding or floating-point conversion."
          },
          "currency": {
            "type": "string"
          },
          "network": {
            "type": "string"
          },
          "networkLabel": {
            "type": "string"
          },
          "expiresAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "addressQrImage": {
            "type": [
              "string",
              "null"
            ]
          },
          "amountQrImage": {
            "type": [
              "string",
              "null"
            ]
          },
          "amountQrPayload": {
            "type": [
              "string",
              "null"
            ]
          },
          "networkFeePaidByCustomer": {
            "type": "boolean"
          }
        },
        "required": [
          "type",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "CheckoutPayment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^gwp_[0-9a-f-]{36}$"
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "requires_action",
              "processing",
              "succeeded",
              "failed",
              "expired",
              "review_required",
              "partially_paid",
              "partially_refunded",
              "refunded",
              "disputed"
            ]
          },
          "providerStatus": {
            "type": "string"
          },
          "fulfillmentReady": {
            "type": "boolean",
            "description": "Only true after exact amount/currency/order binding and provider-confirmed success. A browser redirect is never payment confirmation."
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "createdAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "updatedAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "nextAction": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CheckoutAction"
              },
              {
                "type": "null"
              }
            ]
          },
          "expiresAt": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "authentication": {
            "type": "object",
            "properties": {
              "required": {
                "type": "boolean"
              },
              "expiresAt": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0,
                "description": "Unix timestamp in milliseconds, UTC."
              },
              "attempt": {
                "type": "integer",
                "minimum": 0
              }
            },
            "required": [
              "required",
              "expiresAt",
              "attempt"
            ],
            "additionalProperties": false
          },
          "reason": {
            "type": "string",
            "enum": [
              "amount_mismatch",
              "confirmation_required",
              "refund_mismatch",
              "settlement_unverified"
            ]
          },
          "refundedAmountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          }
        },
        "required": [
          "id",
          "method",
          "status",
          "providerStatus",
          "fulfillmentReady",
          "amountMinor",
          "currency",
          "createdAt",
          "updatedAt",
          "nextAction",
          "expiresAt"
        ],
        "additionalProperties": false
      },
      "SealedCardData": {
        "type": "object",
        "properties": {
          "intent": {
            "type": "string",
            "minLength": 32,
            "maxLength": 8192,
            "description": "Signed, short-lived operation intent from /card-intent; forward unchanged."
          },
          "jwe": {
            "type": "string",
            "maxLength": 14000,
            "pattern": "^[A-Za-z0-9_-]+(?:\\.[A-Za-z0-9_-]+){4}$",
            "description": "Compact JWE using RSA-OAEP-256 and A256GCM. Protected header: kid from the public key, typ=kevmi-card+jwe. Only ciphertext is sent to Kevmi. Never send plaintext card or bank-code fields."
          }
        },
        "required": [
          "intent",
          "jwe"
        ],
        "additionalProperties": false
      },
      "CardIntent": {
        "type": "object",
        "properties": {
          "intent": {
            "type": "string",
            "minLength": 32,
            "maxLength": 8192
          },
          "intentId": {
            "type": "string",
            "maxLength": 100
          },
          "expiresAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          },
          "key": {
            "type": "object",
            "properties": {
              "kid": {
                "type": "string"
              },
              "kty": {
                "type": "string",
                "const": "RSA"
              },
              "n": {
                "type": "string"
              },
              "e": {
                "type": "string"
              },
              "alg": {
                "type": "string",
                "const": "RSA-OAEP-256"
              },
              "use": {
                "type": "string",
                "const": "enc"
              }
            },
            "required": [
              "kid",
              "kty",
              "n",
              "e",
              "alg",
              "use"
            ],
            "additionalProperties": false
          },
          "algorithm": {
            "type": "string",
            "const": "RSA-OAEP-256"
          },
          "encryption": {
            "type": "string",
            "const": "A256GCM"
          },
          "protocol": {
            "type": "string",
            "const": "kevmi-card-v1"
          }
        },
        "required": [
          "intent",
          "intentId",
          "expiresAt",
          "key",
          "algorithm",
          "encryption",
          "protocol"
        ],
        "additionalProperties": false
      },
      "StartCheckoutPayment": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "card"
              },
              "sealed": {
                "$ref": "#/components/schemas/SealedCardData"
              }
            },
            "required": [
              "method",
              "sealed"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "alipay"
              },
              "name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "country": {
                "type": "string",
                "const": "CN"
              },
              "email": {
                "type": "string",
                "format": "email",
                "maxLength": 254
              }
            },
            "required": [
              "method",
              "name",
              "country"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "sbp"
              }
            },
            "required": [
              "method"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "method": {
                "type": "string",
                "const": "crypto"
              },
              "payerCurrency": {
                "type": "string",
                "pattern": "^[A-Z0-9]{2,16}$"
              },
              "network": {
                "type": "string",
                "pattern": "^[a-z0-9_-]{2,32}$"
              }
            },
            "required": [
              "method",
              "payerCurrency",
              "network"
            ],
            "additionalProperties": false
          }
        ]
      },
      "LegacyGatewayEvent": {
        "type": "object",
        "properties": {
          "eventId": {
            "type": "string",
            "maxLength": 100,
            "pattern": "^[A-Za-z0-9_.:-]+$"
          },
          "paymentId": {
            "type": "string",
            "maxLength": 100,
            "pattern": "^[A-Za-z0-9_.:-]+$"
          },
          "invoiceId": {
            "type": "string",
            "pattern": "^lnk_[0-9a-f-]{36}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "succeeded",
              "failed",
              "refunded"
            ]
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991,
            "description": "Integer amount in minor currency units."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "RUB",
              "USDT"
            ],
            "description": "Invoice units: USD cents, RUB kopecks, or hundredths of USDT. No automatic currency conversion."
          },
          "method": {
            "type": "string",
            "enum": [
              "card",
              "alipay",
              "sbp",
              "crypto"
            ]
          },
          "occurredAt": {
            "type": "integer",
            "minimum": 0,
            "description": "Unix timestamp in milliseconds, UTC."
          }
        },
        "required": [
          "eventId",
          "paymentId",
          "invoiceId",
          "status",
          "amountMinor",
          "currency",
          "method",
          "occurredAt"
        ],
        "additionalProperties": false
      },
      "NativeGatewayEvent": {
        "type": "object",
        "required": [
          "id",
          "api_version",
          "mode",
          "type",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "api_version": {
            "type": "string",
            "const": "3"
          },
          "mode": {
            "type": "string",
            "const": "live"
          },
          "type": {
            "type": "string",
            "pattern": "^[a-z_.]{1,80}$"
          },
          "data": {
            "type": "object",
            "required": [
              "id",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "version": {
                "type": "integer",
                "minimum": 0
              },
              "merchant_order_id": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "merchantEvent": {
      "post": {
        "summary": "Verified merchant server delivery",
        "description": "Delivered only to active, challenge-verified endpoints. Raw JSON is signed; verify the timestamp and signature before parsing or changing order state. Return 2xx after durably accepting the event. Persist event IDs to handle duplicates. Network errors, timeout and non-2xx status trigger retries.",
        "parameters": [
          {
            "name": "Kevmi-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kevmi-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Kevmi-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "description": "JSON object. Maximum 16,384 bytes. Unknown fields are rejected.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MerchantEvent"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Accepted durably by the merchant server."
          }
        }
      }
    }
  }
}
