{
  "openapi": "3.1.0",
  "info": {
    "title": "Absolut Pay Merchant API v2 — bank directory and local payins",
    "version": "2.1.0",
    "description": "Signed canonical bank directory. Merchants select bank_id only for payouts; Create Payin does not accept bank_id. Payin formation remains local sandbox only; live adapters are not enabled. HMAC-SHA512 canonicalization is unchanged. POST waits up to 30 seconds; a lost response never authorizes another Create. Merchant webhooks retain v1 wire format; test events are suppressed."
  },
  "servers": [
    {
      "url": "https://api.absolutpay.com",
      "description": "Confirmed HTTPS API origin; business availability is not confirmed."
    }
  ],
  "paths": {
    "/api/v2/payins": {
      "post": {
        "operationId": "createPayinV2",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayin"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Formed Payin with frozen requisite and FX",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payin"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid authentication",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Disallowed source or disabled Shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Merchant order number already reserved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Accepted request failed before formation. webhook_required means neither request nor Shop provided a destination: no gateway dispatch or Payin, and merchant_order_id stays reserved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingWebhook": {
                    "summary": "No request or Shop webhook; permanent rejection",
                    "value": {
                      "error": {
                        "code": "webhook_required",
                        "message": "Provide webhook_url in the request or configure the Shop webhook before creating a new order. This merchant_order_id remains reserved."
                      },
                      "request_id": "example-request-id"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Unavailable or review required; use signed result lookup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "504": {
            "description": "HTTP waiting deadline exceeded; processing is durable; use signed result lookup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/payins/result": {
      "get": {
        "operationId": "lookupPayinRequestV2",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "merchant_order_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A formed Payin or internal request state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RequestResult"
                },
                "examples": {
                  "missingWebhook": {
                    "summary": "Signed lookup of a rejected request; not a Payin status",
                    "value": {
                      "merchant_order_id": "example-order",
                      "state": "failed",
                      "error_code": "webhook_required"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid authentication",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Disallowed source or disabled Shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Result not found in this Shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Unavailable or review required; use signed result lookup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/payins/{id}": {
      "get": {
        "operationId": "getPayinV2",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^ord_[1-9][0-9]*$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Only a formed Payin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payin"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid authentication",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Disallowed source or disabled Shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Result not found in this Shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Unavailable or review required; use signed result lookup",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/banks": {
      "get": {
        "operationId": "listBanksV2",
        "summary": "Get canonical bank IDs for payout integration and issued requisites",
        "description": "Uses the same signed request authentication. Returns no gateway mappings or provider aliases. Use these immutable IDs in the separately agreed payout request contract, not Create Payin. POST /api/v2/payouts creates a payout and reserves funds; it does not itself send a provider transfer. A real automatic payout provider is not enabled by this contract. Directory membership does not guarantee this bank is configured for every shop, method or terminal.",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "Substring of original_name, up to 200 UTF-8 bytes."
          },
          {
            "name": "country_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[A-Z]{2}$"
            }
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^bank_[1-9][0-9]*$",
              "maxLength": 24,
              "description": "Immutable Absolut Pay bank ID from GET /api/v2/banks. Not an NSPK ID or provider code."
            },
            "description": "Use the previous next_after without changing filters. At most 100 items per page."
          }
        ],
        "responses": {
          "200": {
            "description": "Active canonical banks only, ordered by immutable ID. Empty list is valid. next_after is null at the end.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankPage"
                },
                "examples": {
                  "banks": {
                    "value": {
                      "items": [
                        {
                          "id": "bank_1",
                          "original_name": "Т-Банк",
                          "country_code": "RU",
                          "kind": "bank"
                        }
                      ],
                      "next_after": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid, duplicated or unsupported query parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid authentication",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Source IP is not allowed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Directory temporarily unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/payouts": {
      "post": {
        "operationId": "createPayoutV2",
        "description": "Create one payout and atomically reserve principal plus fee under separate Shop payout conditions. This does not itself dispatch a provider transfer.",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Create one payout and atomically reserve principal plus fee under separate Shop payout conditions. This does not itself dispatch a provider transfer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payout input or unknown/duplicate JSON fields (invalid_payout_request).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid token, signature, timestamp or nonce.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Disallowed source, disabled Shop or separate payout configuration disabled (payout_configuration_disabled).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Duplicate permanent merchant order number or nonce replay. Recover with a fresh signed result lookup; never repeat creation with new fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Insufficient available funds for frozen principal plus commission (insufficient_funds); merchant_order_id remains reserved.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable; use a new signed result lookup before any next action.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayout"
              }
            }
          }
        }
      }
    },
    "/api/v2/payouts/result": {
      "get": {
        "operationId": "lookupPayoutRequestV2",
        "description": "Look up this Shop permanent creation outcome using a fresh nonce.",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "merchant_order_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Look up this Shop permanent creation outcome using a fresh nonce.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutRequestResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payout input or unknown/duplicate JSON fields (invalid_payout_request).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid token, signature, timestamp or nonce.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Disallowed source, disabled Shop or separate payout configuration disabled (payout_configuration_disabled).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No request for this merchant_order_id in the authenticated Shop (payout_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Duplicate permanent merchant order number or nonce replay. Recover with a fresh signed result lookup; never repeat creation with new fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable; use a new signed result lookup before any next action.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/payouts/{id}": {
      "get": {
        "operationId": "getPayoutV2",
        "description": "Retrieve only the authenticated Shop payout, with frozen bank/recipient/rate/commission and current execution status.",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
              "description": "Permanent UUID v4 issued by Absolut Pay."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Retrieve only the authenticated Shop payout, with frozen bank/recipient/rate/commission and current execution status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payout input or unknown/duplicate JSON fields (invalid_payout_request).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid token, signature, timestamp or nonce.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Disallowed source, disabled Shop or separate payout configuration disabled (payout_configuration_disabled).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Payout does not exist in the authenticated Shop (payout_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Duplicate permanent merchant order number or nonce replay. Recover with a fresh signed result lookup; never repeat creation with new fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable; use a new signed result lookup before any next action.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/balance": {
      "get": {
        "operationId": "getShopBalanceV2",
        "description": "Read exact available, reserved and total USDT for the authenticated Shop. No shop_id query parameter is accepted.",
        "parameters": [
          {
            "name": "X-API-Token",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Nonce",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Read exact available, reserved and total USDT for the authenticated Shop. No shop_id query parameter is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Balance"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payout input or unknown/duplicate JSON fields (invalid_payout_request).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Invalid token, signature, timestamp or nonce.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Disallowed source, disabled Shop or separate payout configuration disabled (payout_configuration_disabled).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Authenticated Shop balance projection not found (payout_not_found).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Duplicate permanent merchant order number or nonce replay. Recover with a fresh signed result lookup; never repeat creation with new fields.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Temporarily unavailable; use a new signed result lookup before any next action.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CreatePayin": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "merchant_order_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
            "maxLength": 80,
            "not": {
              "pattern": "^0(\\.0+)?$"
            }
          },
          "currency": {
            "enum": [
              "RUB",
              "AZN",
              "KZT",
              "KGS",
              "UZS"
            ]
          },
          "method_id": {
            "type": "integer",
            "enum": [
              1,
              2,
              3,
              4
            ]
          },
          "mode": {
            "enum": [
              "h2h",
              "payment_form"
            ]
          },
          "traffic_type": {
            "enum": [
              "primary",
              "secondary"
            ]
          },
          "payer": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "id": {
                "type": "string",
                "minLength": 1,
                "maxLength": 128
              },
              "ip": {
                "type": "string",
                "description": "IPv4 or IPv6 address without a zone.",
                "anyOf": [
                  {
                    "format": "ipv4"
                  },
                  {
                    "format": "ipv6"
                  }
                ]
              },
              "email": {
                "type": "string",
                "minLength": 1,
                "maxLength": 254
              },
              "phone": {
                "type": "string",
                "minLength": 1,
                "maxLength": 32
              },
              "user_agent": {
                "type": "string",
                "minLength": 1,
                "maxLength": 1024
              },
              "fingerprint": {
                "type": "string",
                "minLength": 1,
                "maxLength": 256
              }
            },
            "required": [
              "id",
              "ip"
            ]
          },
          "metadata": {
            "type": "object",
            "description": "At most 16384 UTF-8 bytes; duplicate keys are forbidden."
          },
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://",
            "maxLength": 2048,
            "description": "Optional HTTPS override; takes priority over the Shop default captured during preparation. If neither destination exists, the accepted request fails with HTTP 422 webhook_required before gateway dispatch or Payin formation. Its merchant_order_id remains permanently reserved; later Shop edits never restart it."
          },
          "redirect_urls": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "success": {
                "type": "string",
                "format": "uri",
                "pattern": "^https://",
                "maxLength": 2048
              },
              "failure": {
                "type": "string",
                "format": "uri",
                "pattern": "^https://",
                "maxLength": 2048
              },
              "return": {
                "type": "string",
                "format": "uri",
                "pattern": "^https://",
                "maxLength": 2048
              }
            },
            "required": []
          }
        },
        "required": [
          "merchant_order_id",
          "amount",
          "currency",
          "method_id",
          "mode",
          "traffic_type",
          "payer"
        ]
      },
      "MockRequisite": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "type": {
            "const": "mock"
          },
          "value": {
            "const": "TEST-ONLY-NOT-PAYABLE"
          },
          "bank_id": {
            "type": "string",
            "pattern": "^bank_[1-9][0-9]*$",
            "maxLength": 24,
            "description": "Immutable Absolut Pay bank ID from GET /api/v2/banks. Not an NSPK ID or provider code."
          },
          "bank_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Frozen original_name of the issued canonical bank; not the raw provider alias."
          }
        },
        "required": [
          "type",
          "value"
        ],
        "dependentRequired": {
          "bank_id": [
            "bank_name"
          ],
          "bank_name": [
            "bank_id"
          ]
        }
      },
      "Payin": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^ord_[1-9][0-9]*$"
          },
          "merchant_order_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "status_id": {
            "type": "integer",
            "enum": [
              1,
              2,
              3,
              4
            ],
            "description": "1 created; 2 success; 3 overdue; 4 cancel."
          },
          "amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
            "maxLength": 80,
            "not": {
              "pattern": "^0(\\.0+)?$"
            }
          },
          "currency": {
            "enum": [
              "RUB",
              "AZN",
              "KZT",
              "KGS",
              "UZS"
            ]
          },
          "method_id": {
            "type": "integer",
            "enum": [
              1,
              2,
              3,
              4
            ]
          },
          "mode": {
            "enum": [
              "h2h",
              "payment_form"
            ]
          },
          "traffic_type": {
            "enum": [
              "primary",
              "secondary"
            ]
          },
          "rate": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
            "maxLength": 80,
            "not": {
              "pattern": "^0(\\.0+)?$"
            }
          },
          "fee": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
            "maxLength": 80,
            "description": "Frozen fee percentage, not a currency amount."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "is_test": {
            "const": true
          },
          "requisite": {
            "$ref": "#/components/schemas/MockRequisite"
          },
          "payment_url": {
            "type": "string",
            "format": "uri",
            "description": "Platform capability URL; never a provider URL."
          },
          "success_paid": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
            "maxLength": 80,
            "not": {
              "pattern": "^0(\\.0+)?$"
            }
          },
          "paid_at": {
            "type": "string",
            "format": "date-time"
          },
          "close_reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "bank_id": {
            "type": "string",
            "pattern": "^bank_[1-9][0-9]*$",
            "maxLength": 24,
            "description": "Immutable Absolut Pay bank ID from GET /api/v2/banks. Not an NSPK ID or provider code."
          },
          "bank_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Frozen original_name of the issued canonical bank; not the raw provider alias."
          }
        },
        "required": [
          "id",
          "merchant_order_id",
          "status_id",
          "amount",
          "currency",
          "method_id",
          "mode",
          "traffic_type",
          "rate",
          "fee",
          "created_at",
          "expires_at",
          "is_test"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "mode": {
                  "const": "h2h"
                }
              }
            },
            "then": {
              "required": [
                "requisite"
              ],
              "not": {
                "required": [
                  "payment_url"
                ]
              }
            },
            "else": {
              "required": [
                "payment_url"
              ],
              "not": {
                "required": [
                  "requisite"
                ]
              }
            }
          },
          {
            "if": {
              "properties": {
                "status_id": {
                  "const": 2
                }
              }
            },
            "then": {
              "required": [
                "success_paid",
                "paid_at"
              ]
            },
            "else": {
              "not": {
                "anyOf": [
                  {
                    "required": [
                      "success_paid"
                    ]
                  },
                  {
                    "required": [
                      "paid_at"
                    ]
                  }
                ]
              }
            }
          },
          {
            "if": {
              "properties": {
                "status_id": {
                  "const": 4
                }
              }
            },
            "then": {
              "required": [
                "close_reason"
              ]
            },
            "else": {
              "not": {
                "required": [
                  "close_reason"
                ]
              }
            }
          }
        ],
        "dependentRequired": {
          "bank_id": [
            "bank_name"
          ],
          "bank_name": [
            "bank_id"
          ]
        }
      },
      "RequestResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "merchant_order_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "state": {
            "enum": [
              "processing",
              "completed",
              "failed",
              "review_required"
            ]
          },
          "payin": {
            "$ref": "#/components/schemas/Payin"
          },
          "error_code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Merchant-safe failure code. webhook_required is a terminal rejection without Payin; adding a destination later does not retry the reserved request."
          }
        },
        "required": [
          "merchant_order_id",
          "state"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "state": {
                  "const": "completed"
                }
              }
            },
            "then": {
              "required": [
                "payin"
              ]
            },
            "else": {
              "not": {
                "required": [
                  "payin"
                ]
              }
            }
          },
          {
            "if": {
              "properties": {
                "state": {
                  "const": "failed"
                }
              }
            },
            "then": {
              "required": [
                "error_code"
              ]
            },
            "else": {
              "not": {
                "required": [
                  "error_code"
                ]
              }
            }
          }
        ]
      },
      "Error": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "code": {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              "message": {
                "type": "string",
                "minLength": 1,
                "maxLength": 500
              }
            },
            "required": [
              "code",
              "message"
            ]
          },
          "request_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          }
        },
        "required": [
          "error",
          "request_id"
        ]
      },
      "Bank": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^bank_[1-9][0-9]*$",
            "maxLength": 24,
            "description": "Immutable Absolut Pay bank ID from GET /api/v2/banks. Not an NSPK ID or provider code."
          },
          "original_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "country_code": {
            "type": [
              "string",
              "null"
            ],
            "pattern": "^[A-Z]{2}$"
          },
          "kind": {
            "type": "string",
            "enum": [
              "bank",
              "wallet",
              "mobile",
              "other"
            ]
          }
        },
        "required": [
          "id",
          "original_name",
          "country_code",
          "kind"
        ]
      },
      "BankPage": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "items": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/Bank"
            }
          },
          "next_after": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^bank_[1-9][0-9]*$",
                "maxLength": 24,
                "description": "Immutable Absolut Pay bank ID from GET /api/v2/banks. Not an NSPK ID or provider code."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "items",
          "next_after"
        ]
      },
      "PayoutRecipient": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "card_number": {
            "type": "string",
            "pattern": "^[0-9]{12,19}$"
          },
          "phone_number": {
            "type": "string",
            "pattern": "^\\+[1-9][0-9]{7,14}$"
          },
          "account_number": {
            "type": "string",
            "pattern": "^[A-Z0-9]{8,34}$"
          },
          "customer_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "customer_name"
        ],
        "description": "Exactly one destination field is accepted for the selected payout method; account payouts execute manually until a reviewed provider protocol supports them."
      },
      "CreatePayout": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "merchant_order_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]{0,17})(\\.[0-9]{1,2})?$",
            "not": {
              "pattern": "^0(\\.0+)?$"
            }
          },
          "currency": {
            "enum": [
              "RUB",
              "AZN",
              "KZT",
              "KGS",
              "UZS"
            ]
          },
          "method": {
            "enum": [
              "sbp",
              "card",
              "account"
            ]
          },
          "bank_id": {
            "type": "string",
            "pattern": "^bank_[1-9][0-9]*$",
            "maxLength": 24,
            "description": "Immutable Absolut Pay bank ID from GET /api/v2/banks. Not an NSPK ID or provider code."
          },
          "recipient": {
            "$ref": "#/components/schemas/PayoutRecipient"
          },
          "metadata": {
            "type": "object",
            "description": "At most 16384 UTF-8 bytes. Duplicate JSON keys are forbidden; nesting is at most 32 levels."
          },
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://",
            "maxLength": 2000,
            "description": "Optional HTTPS destination override, port 443 only, without credentials or fragment. The Shop default is captured when omitted. A payout can be created without a webhook destination; poll its signed result instead."
          }
        },
        "required": [
          "merchant_order_id",
          "amount",
          "currency",
          "method",
          "recipient"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "method": {
                  "const": "sbp"
                }
              },
              "required": [
                "method"
              ]
            },
            "then": {
              "properties": {
                "recipient": {
                  "required": [
                    "phone_number"
                  ],
                  "not": {
                    "anyOf": [
                      {
                        "required": [
                          "card_number"
                        ]
                      },
                      {
                        "required": [
                          "account_number"
                        ]
                      }
                    ]
                  }
                }
              },
              "required": [
                "bank_id"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "method": {
                  "const": "card"
                }
              },
              "required": [
                "method"
              ]
            },
            "then": {
              "properties": {
                "recipient": {
                  "required": [
                    "card_number"
                  ],
                  "not": {
                    "anyOf": [
                      {
                        "required": [
                          "phone_number"
                        ]
                      },
                      {
                        "required": [
                          "account_number"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "method": {
                  "const": "account"
                }
              },
              "required": [
                "method"
              ]
            },
            "then": {
              "properties": {
                "recipient": {
                  "required": [
                    "account_number"
                  ],
                  "not": {
                    "anyOf": [
                      {
                        "required": [
                          "phone_number"
                        ]
                      },
                      {
                        "required": [
                          "card_number"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        ],
        "description": "Shop identity comes from the signed API token. Rate and commission come from the separate active payout configuration and cannot be supplied by the client. Principal plus commission is atomically reserved in USDT. Merchant order numbers remain permanently reserved even after creation rejection or loss of response. Never create another payout to recover an unknown transfer."
      },
      "Payout": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "metadata": {
            "type": "object",
            "description": "At most 16384 UTF-8 bytes. Duplicate JSON keys are forbidden; nesting is at most 32 levels."
          },
          "id": {
            "type": "string",
            "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
            "description": "Permanent UUID v4 issued by Absolut Pay."
          },
          "merchant_order_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{2}$",
            "maxLength": 80,
            "description": "Exact source-currency amount with two decimal places.",
            "not": {
              "const": "0.00"
            }
          },
          "currency": {
            "enum": [
              "RUB",
              "AZN",
              "KZT",
              "KGS",
              "UZS"
            ]
          },
          "method": {
            "enum": [
              "sbp",
              "card",
              "account"
            ]
          },
          "bank_id": {
            "type": "string",
            "pattern": "^bank_[1-9][0-9]*$",
            "maxLength": 24,
            "description": "Immutable Absolut Pay bank ID from GET /api/v2/banks. Not an NSPK ID or provider code."
          },
          "bank_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Frozen original_name of the selected canonical bank."
          },
          "recipient": {
            "$ref": "#/components/schemas/PayoutRecipient"
          },
          "status": {
            "enum": [
              "queued",
              "processing",
              "unknown",
              "success",
              "failed",
              "cancelled",
              "partial"
            ],
            "description": "unknown retains the reserve; partial means some parts succeeded or the final part outcomes differ. Remainder includes unpaid failed/cancelled parts and is not automatically reissued."
          },
          "principal_usdt": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places.",
            "not": {
              "const": "0.00000000"
            }
          },
          "fee_usdt": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places."
          },
          "total_usdt": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places.",
            "not": {
              "const": "0.00000000"
            }
          },
          "rate_fiat_per_usdt": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Frozen source-currency units per USDT; subsequent configuration edits cannot recalculate an existing payout.",
            "not": {
              "const": "0.00000000"
            }
          },
          "fee_percent": {
            "type": "string",
            "pattern": "^(?:(?:0|[1-9][0-9]?)\\.[0-9]{8}|100\\.00000000)$",
            "description": "Frozen percentage, not a currency amount."
          },
          "paid_amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{2}$",
            "maxLength": 80,
            "description": "Exact source-currency amount with two decimal places."
          },
          "remainder": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{2}$",
            "maxLength": 80,
            "description": "Exact source-currency amount with two decimal places."
          },
          "revision": {
            "type": "integer",
            "minimum": 1
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "metadata",
          "id",
          "merchant_order_id",
          "amount",
          "currency",
          "method",
          "recipient",
          "status",
          "principal_usdt",
          "fee_usdt",
          "total_usdt",
          "rate_fiat_per_usdt",
          "fee_percent",
          "paid_amount",
          "remainder",
          "revision",
          "created_at",
          "updated_at"
        ],
        "dependentRequired": {
          "bank_id": [
            "bank_name"
          ],
          "bank_name": [
            "bank_id"
          ]
        },
        "allOf": [
          {
            "if": {
              "properties": {
                "method": {
                  "const": "sbp"
                }
              },
              "required": [
                "method"
              ]
            },
            "then": {
              "properties": {
                "recipient": {
                  "required": [
                    "phone_number"
                  ],
                  "not": {
                    "anyOf": [
                      {
                        "required": [
                          "card_number"
                        ]
                      },
                      {
                        "required": [
                          "account_number"
                        ]
                      }
                    ]
                  }
                }
              },
              "required": [
                "bank_id",
                "bank_name"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "method": {
                  "const": "card"
                }
              },
              "required": [
                "method"
              ]
            },
            "then": {
              "properties": {
                "recipient": {
                  "required": [
                    "card_number"
                  ],
                  "not": {
                    "anyOf": [
                      {
                        "required": [
                          "phone_number"
                        ]
                      },
                      {
                        "required": [
                          "account_number"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "method": {
                  "const": "account"
                }
              },
              "required": [
                "method"
              ]
            },
            "then": {
              "properties": {
                "recipient": {
                  "required": [
                    "account_number"
                  ],
                  "not": {
                    "anyOf": [
                      {
                        "required": [
                          "phone_number"
                        ]
                      },
                      {
                        "required": [
                          "card_number"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          }
        ],
        "description": "Merchant-safe payout projection. It excludes provider keys, references, dispatch attempts, internal part/accounting IDs, staff details and execution evidence. Amounts remain strings."
      },
      "PayoutRequestResult": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "status": {
            "enum": [
              "creating",
              "created",
              "rejected"
            ]
          },
          "payout": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Payout"
              },
              {
                "type": "null"
              }
            ]
          },
          "error_code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        },
        "required": [
          "status",
          "payout"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "status": {
                  "const": "created"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "properties": {
                "payout": {
                  "$ref": "#/components/schemas/Payout"
                }
              }
            },
            "else": {
              "properties": {
                "payout": {
                  "type": "null"
                }
              }
            }
          },
          {
            "if": {
              "properties": {
                "status": {
                  "const": "rejected"
                }
              },
              "required": [
                "status"
              ]
            },
            "then": {
              "required": [
                "error_code"
              ]
            },
            "else": {
              "not": {
                "required": [
                  "error_code"
                ]
              }
            }
          }
        ],
        "description": "Durable creation outcome, distinct from payout execution status. Retrieve this after timeout/503/duplicate; creating or rejected does not mean permission to submit the same number with changed parameters."
      },
      "PayoutWebhook": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "event_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
            "description": "Permanent UUID v4 issued by Absolut Pay."
          },
          "event_type": {
            "const": "payout.updated"
          },
          "revision": {
            "type": "integer",
            "minimum": 1
          },
          "payout_id": {
            "type": "string",
            "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
            "description": "Permanent UUID v4 issued by Absolut Pay."
          },
          "merchant_order_id": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "status": {
            "enum": [
              "queued",
              "processing",
              "unknown",
              "success",
              "failed",
              "cancelled",
              "partial"
            ],
            "description": "unknown retains the reserve; partial means some parts succeeded or the final part outcomes differ. Remainder includes unpaid failed/cancelled parts and is not automatically reissued."
          },
          "amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{2}$",
            "maxLength": 80,
            "description": "Exact source-currency amount with two decimal places.",
            "not": {
              "const": "0.00"
            }
          },
          "currency": {
            "enum": [
              "RUB",
              "AZN",
              "KZT",
              "KGS",
              "UZS"
            ]
          },
          "paid_amount": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{2}$",
            "maxLength": 80,
            "description": "Exact source-currency amount with two decimal places."
          },
          "remainder": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{2}$",
            "maxLength": 80,
            "description": "Exact source-currency amount with two decimal places."
          },
          "principal_usdt": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places.",
            "not": {
              "const": "0.00000000"
            }
          },
          "fee_usdt": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "event_id",
          "event_type",
          "revision",
          "payout_id",
          "merchant_order_id",
          "status",
          "amount",
          "currency",
          "paid_amount",
          "remainder",
          "principal_usdt",
          "fee_usdt",
          "updated_at"
        ],
        "description": "At-least-once committed workflow update. Deduplicate event_id and apply only a newer revision for the payout. A payout notification cannot authorize a new transfer. Verify HMAC-SHA512 over X-Webhook-Timestamp + \".\" + exact body bytes using the Shop API secret, then return HTTP 200 only after durable application."
      },
      "Balance": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "currency": {
            "const": "USDT"
          },
          "available": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places."
          },
          "reserved": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places."
          },
          "total": {
            "type": "string",
            "pattern": "^(0|[1-9][0-9]*)\\.[0-9]{8}$",
            "maxLength": 80,
            "description": "Exact USDT amount with eight decimal places."
          }
        },
        "required": [
          "currency",
          "available",
          "reserved",
          "total"
        ],
        "description": "One Shop only, selected by the signed API token. Total equals available plus reserved, including pending payout principal and fee."
      }
    }
  },
  "webhooks": {
    "payoutUpdated": {
      "post": {
        "operationId": "receivePayoutUpdateV2",
        "description": "Destination is the captured request/Shop webhook URL. The delivery worker retries up to eight attempts after network/non-200 results. Do not resend payouts when notifications are missing. Verify signature over timestamp and exact raw body; deduplicate event_id and honor revision.",
        "parameters": [
          {
            "name": "X-Webhook-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]+$"
            }
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutWebhook"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Update durably accepted, including an already applied duplicate."
          }
        }
      }
    }
  }
}
