{
  "openapi": "3.1.0",
  "info": {
    "title": "MONA Pay API v1",
    "version": "1.0",
    "description": "MONA Pay là cổng thanh toán và API ngân hàng của The MONA Group, giúp doanh nghiệp Việt Nam nhận và xác nhận tiền chuyển khoản theo thời gian thực qua tài khoản ảo (VA), VietQR, webhook, Telegram, nhóm Zalo và email. Tiền không đi qua MONA Pay. Tài liệu: https://monapay.vn/docs · llms.txt: https://monapay.vn/llms.txt",
    "contact": {
      "name": "MONA Pay",
      "url": "https://monapay.vn",
      "email": "info@themona.global"
    }
  },
  "servers": [
    {
      "url": "https://api.monapay.vn",
      "description": "Production"
    },
    {
      "url": "https://ipn.mona.host",
      "description": "Alias cũ (vẫn chạy)"
    }
  ],
  "paths": {
    "/api/v1/client/register-client": {
      "post": {
        "tags": [
          "Clients"
        ],
        "summary": "Register Client",
        "operationId": "register_client_api_v1_client_register_client_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Response"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "title": "Response Register Client Api V1 Client Register Client Post"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error."
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request."
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/client/login": {
      "post": {
        "tags": [
          "Clients"
        ],
        "summary": "Login",
        "description": "Login to get access token",
        "operationId": "login_api_v1_client_login_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response",
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Response"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "title": "Response Login Api V1 Client Login Post"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error."
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request."
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/client/me": {
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "Get Current Client",
        "description": "Get current logged in client info",
        "operationId": "get_current_client_api_v1_client_me_get",
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response",
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Response"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "title": "Response Get Current Client Api V1 Client Me Get"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error."
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request."
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/client/bank-accounts": {
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "List Bank Accounts",
        "description": "Danh sách bank account của client đang đăng nhập (Bearer token)",
        "operationId": "list_bank_accounts_api_v1_client_bank_accounts_get",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "description": "Page number",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Page size",
              "default": 10,
              "title": "Limit"
            },
            "description": "Page size"
          }
        ],
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Response"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "title": "Response List Bank Accounts Api V1 Client Bank Accounts Get",
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error."
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request."
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/client/change-password": {
      "put": {
        "tags": [
          "Clients"
        ],
        "summary": "Change Own Password",
        "description": "Change user password (Self)",
        "operationId": "change_own_password_api_v1_client_change_password_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangePasswordRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response",
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/Response"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "title": "Response Change Own Password Api V1 Client Change Password Put"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error."
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request."
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/client-keys/generate": {
      "post": {
        "tags": [
          "Client Keys"
        ],
        "summary": "Generate Key",
        "operationId": "generate_key_api_v1_client_keys_generate_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateKeyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/client-keys/list": {
      "get": {
        "tags": [
          "Client Keys"
        ],
        "summary": "List Keys",
        "operationId": "list_keys_api_v1_client_keys_list_get",
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/client-keys/destroy/{key_id}": {
      "delete": {
        "tags": [
          "Client Keys"
        ],
        "summary": "Destroy Key",
        "operationId": "destroy_key_api_v1_client_keys_destroy__key_id__delete",
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Key Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/virtual-account/registration": {
      "post": {
        "tags": [
          "ACB VA Banking"
        ],
        "summary": "Đăng ký tài khoản VA",
        "description": "Đối tác gọi API này của ACB để gửi yêu cầu đăng ký tài khoản VA.\n            ACB sẽ nhận và kiểm tra thông tin đầu vào.\n            Yêu cầu:\n            Phải truyền đầy đủ các thông tin bắt buộc.\n            Mã đăng ký dịch vụ phải trùng khớp với thông tin đăng ký trong hệ thống và còn đang hoạt động",
        "operationId": "virtual_account_registration_api_v1_acb_virtual_account_registration_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VirtualAccountRegistrationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/{acb_request_id}/virtual-account/verification": {
      "post": {
        "tags": [
          "ACB VA Banking"
        ],
        "summary": "Xác thực đăng ký/hủy tài khoản định danh",
        "description": "Đối tác gọi API này của ACB để gửi yêu cầu thông tin tài khoản định danh.\n            ACB sẽ nhận và kiểm tra thông tin đầu vào.\n            Yêu cầu:\n            Phải truyền đầy đủ các thông tin bắt buộc.\n            Mã xác thực phải trùng khớp với mã hệ thống đã gửi cho khách hàng.",
        "operationId": "virtual_account_verification_api_v1_acb__acb_request_id__virtual_account_verification_post",
        "parameters": [
          {
            "name": "acb_request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Acb Request Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Body_virtual_account_verification_api_v1_acb__acb_request_id__virtual_account_verification_post"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/virtual-account/transactions": {
      "get": {
        "tags": [
          "ACB VA Banking"
        ],
        "summary": "Danh sách giao dịch của VA",
        "description": "Trả về giao dịch RTXN đã lưu theo `virtual_account_number`.\n            Hệ thống lấy VA nội bộ theo số VA, kiểm tra quyền sở hữu rồi join transaction.\n            Phân trang: `page`, `limit`.",
        "operationId": "list_va_transactions_api_v1_acb_virtual_account_transactions_get",
        "parameters": [
          {
            "name": "virtual_account_number",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Virtual Account number",
              "title": "Virtual Account Number"
            },
            "description": "Virtual Account number"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "description": "Page number",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Page size",
              "default": 10,
              "title": "Limit"
            },
            "description": "Page size"
          }
        ],
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/{virtual_account_id}/virtual-account/delete": {
      "post": {
        "tags": [
          "ACB VA Banking"
        ],
        "summary": "Hủy tài khoản VA",
        "description": "Đối tác gọi API này của ACB để gửi yêu cầu hủy tài khoản VA.\n            ACB sẽ nhận và kiểm tra thông tin đầu vào.\n            Yêu cầu:\n            Phải truyền đầy đủ các thông tin bắt buộc.\n            Mã đăng ký dịch vụ phải trùng khớp với thông tin đăng ký trong hệ thống và còn đang hoạt động",
        "operationId": "delete_api_v1_acb__virtual_account_id__virtual_account_delete_post",
        "parameters": [
          {
            "name": "virtual_account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Virtual Account Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/{bank_account_id}/virtual-account/retrieve": {
      "get": {
        "tags": [
          "ACB VA Banking"
        ],
        "summary": "Truy vấn danh sách tài khoản VA",
        "description": "Đối tác gọi API này của ACB để truy vấn danh sách tài khoản VA",
        "operationId": "retrieve_api_v1_acb__bank_account_id__virtual_account_retrieve_get",
        "parameters": [
          {
            "name": "bank_account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Bank Account Id"
            }
          },
          {
            "name": "virtual_account_number",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Virtual Account number",
              "title": "Virtual Account Number"
            },
            "description": "Virtual Account number"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "description": "Page number, default is 1",
              "default": 1,
              "title": "Page"
            },
            "description": "Page number, default is 1"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "description": "Page size, default is 10",
              "default": 10,
              "title": "Limit"
            },
            "description": "Page size, default is 10"
          }
        ],
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/{virtual_account_id}/notification/registration": {
      "post": {
        "tags": [
          "ACB IPN Banking"
        ],
        "summary": "Đăng ký dịch vụ thông báo giao dịch",
        "description": "Đối tác gọi API này của ACB để gửi yêu cầu đăng ký dịch vụ thông báo giao dịch.\n            ACB sẽ nhận và kiểm tra thông tin đầu vào.\n            Yêu cầu:\n            Phải truyền đầy đủ các thông tin bắt buộc.",
        "operationId": "notification_registration_api_v1_acb__virtual_account_id__notification_registration_post",
        "parameters": [
          {
            "name": "virtual_account_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Virtual Account Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationRegistrationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/{acb_request_id}/notification/verification": {
      "post": {
        "tags": [
          "ACB IPN Banking"
        ],
        "summary": "Xác thực đăng ký/cập nhật/hủy dịch vụ thông báo",
        "description": "Đối tác gọi API này của ACB để gửi yêu cầu đăng ký dịch vụ thông báo giao dịch.\n            ACB sẽ nhận và kiểm tra thông tin đầu vào.\n            Yêu cầu:\n            Phải truyền đầy đủ các thông tin bắt buộc.\n            Mã xác thực phải trùng khớp với mã hệ thống đã gửi cho khách hàng.",
        "operationId": "notification_verification_api_v1_acb__acb_request_id__notification_verification_post",
        "parameters": [
          {
            "name": "acb_request_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Acb Request Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Body_notification_verification_api_v1_acb__acb_request_id__notification_verification_post"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/{acb_notification_id}/notification/modification": {
      "post": {
        "tags": [
          "ACB IPN Banking"
        ],
        "summary": "Cập nhật dịch vụ thông báo giao dịch",
        "description": "Đối tác gọi API này của ACB để gửi yêu cầu cập nhật dịch vụ thông báo giao dịch.\n            ACB sẽ nhận và kiểm tra thông tin đầu vào.\n            Yêu cầu:\n            Phải truyền đầy đủ các thông tin bắt buộc.",
        "operationId": "notification_modification_api_v1_acb__acb_notification_id__notification_modification_post",
        "parameters": [
          {
            "name": "acb_notification_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Acb Notification Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotificationRegistrationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/{acb_notification_id}/notification/delete": {
      "post": {
        "tags": [
          "ACB IPN Banking"
        ],
        "summary": "Hủy đăng ký dịch vụ thông báo giao dịch",
        "description": "Đối tác gọi API này của ACB để gửi yêu cầu hủy đăng ký dịch vụ thông báo giao dịch\n        ACB sẽ nhận và kiểm tra thông tin đầu vào.\n        Yêu cầu:\n        Phải truyền đầy đủ các thông tin bắt buộc.\n        Mã đăng ký dịch vụ trùng khớp với thông tin lưu trong hệ thống và còn đang hoạt động\n        Loại dịch vụ hủy trùng khớp với dịch vụ ACB cung cấp và được đăng ký dịch vụ tại ACB",
        "operationId": "delete_api_v1_acb__acb_notification_id__notification_delete_post",
        "parameters": [
          {
            "name": "acb_notification_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Acb Notification Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/qr-payment/generate": {
      "post": {
        "tags": [
          "ACB QR Banking"
        ],
        "summary": "Khởi tạo QR Code",
        "description": "Đây là chuẩn ACB cung cấp cho doanh nghiệp để doanh nghiệp xây dựng API theo chuẩn này với mục đích gọi sang hệ thống ACB cung cấp thông tin đơn hàng thanh toán cần tạo QRCode. Điều kiện cần:\n            \n            Số tài khoản hưởng là tài khoản của doanh nghiệp và đã có đăng ký Tài khoản định danh trên hệ thống ACB.\n            QR Code được doanh nghiệp thể hiện phải có các thông tin:\n            Dòng cảnh báo người thanh toán ”Quý khách vui lòng kiểm tra thông tin thanh tóan trước khi thực hiện giao dịch”.\n            Số tiền cần phải thanh toán in Đậm và kích cỡ lớn.",
        "operationId": "qr_payment_generate_api_v1_acb_qr_payment_generate_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QRPaymentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Kết quả tạo QR, có qr_image_url trỏ tới ảnh PNG public.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "required": [
                        "qr_image_url"
                      ],
                      "properties": {
                        "qr_image_url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Ảnh PNG public của QR."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/acb/qr-payment/{qr_code_id}/cancellation": {
      "delete": {
        "tags": [
          "ACB QR Banking"
        ],
        "summary": "Hủy QR Code",
        "description": "Chuẩn kỹ thuật này được ACB cung cấp cho các doanh nghiệp để doanh nghiệp xây dựng API gọi về hệ thống ACB thực hiện hủy QR Code tạo nhưng chưa thực hiện thanh toán.",
        "operationId": "qr_payment_cancellation_api_v1_acb_qr_payment__qr_code_id__cancellation_delete",
        "parameters": [
          {
            "name": "qr_code_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Qr Code Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QRCancelRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK - The request has succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - The server cannot or will not process the request due to a client error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication is required and has failed or has not been provided.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - The server encountered an unexpected condition that prevented it from fulfilling the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Response"
                }
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Health Check",
        "operationId": "health_check_health_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        },
        "security": [
          {
            "Bearer Auth": []
          }
        ]
      }
    },
    "/api/v1/billing/plans": {
      "get": {
        "tags": [
          "billing"
        ],
        "summary": "Danh sách 5 gói (public, không cần đăng nhập)",
        "security": [],
        "responses": {
          "200": {
            "description": "5 gói: code, name, price_month, price_year (= price_month × 10), tx_limit, overage_per_tx, features",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/usage": {
      "get": {
        "tags": [
          "billing"
        ],
        "summary": "Mức dùng tháng hiện tại của client",
        "description": "Giao dịch = 1 khoản tiền VÀO ghi nhận trên mọi tài khoản/VA đã nối, cắt tháng theo giờ Việt Nam (UTC+7). Sandbox và webhook gửi lại không tính.",
        "responses": {
          "200": {
            "description": "plan_code, plan_cycle, plan_expires_at, tx_used, tx_limit, overage_tx, overage_amount",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/invoices": {
      "get": {
        "tags": [
          "billing"
        ],
        "summary": "Danh sách hoá đơn (phân trang, mới nhất trước)",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ data: [...], total }",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "billing"
        ],
        "summary": "Tạo hoá đơn nâng gói (cần X-Client-Secret)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "plan_code",
                  "cycle"
                ],
                "properties": {
                  "plan_code": {
                    "type": "string",
                    "enum": [
                      "startup",
                      "business",
                      "enterprise",
                      "scale"
                    ]
                  },
                  "cycle": {
                    "type": "string",
                    "enum": [
                      "month",
                      "year"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Hoá đơn pending, hạn 48h, mã chuyển khoản MPAY + 6 số, kèm payment: ảnh VietQR + payload EMVCo. Chuyển đúng số tiền với nội dung là mã MPAY, hệ tự khớp trong vài giây.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/invoices/{invoice_id}": {
      "get": {
        "tags": [
          "billing"
        ],
        "summary": "Chi tiết hoá đơn (poll trạng thái paid)",
        "parameters": [
          {
            "name": "invoice_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Hoá đơn + payment nếu còn pending; status: pending | paid | cancelled | expired",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/invoices/{invoice_id}/cancel": {
      "post": {
        "tags": [
          "billing"
        ],
        "summary": "Huỷ hoá đơn pending (cần X-Client-Secret)",
        "parameters": [
          {
            "name": "invoice_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "pending → cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/email-configs": {
      "get": {
        "tags": [
          "Email"
        ],
        "summary": "Danh sách cấu hình email",
        "operationId": "list_email_configs",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope với data là EmailConfig[].",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/EmailConfig"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Email"
        ],
        "summary": "Tạo cấu hình email",
        "operationId": "create_email_config",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Tạo ở trạng thái chưa hoạt động nếu còn địa chỉ chưa xác minh. Hệ thống tự gửi mã 6 số, hạn 15 phút, tới từng địa chỉ mới.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailConfigCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "data có pending_verification cho địa chỉ còn chờ mã.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/EmailConfig"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key đã dùng với body khác."
          },
          "422": {
            "description": "Dữ liệu không hợp lệ hoặc quá 10 người nhận."
          }
        }
      }
    },
    "/api/v1/email-configs/{id}": {
      "get": {
        "tags": [
          "Email"
        ],
        "summary": "Chi tiết cấu hình email",
        "operationId": "get_email_config",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope với data là EmailConfig.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/EmailConfig"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Không tìm thấy cấu hình thuộc client."
          }
        }
      },
      "put": {
        "tags": [
          "Email"
        ],
        "summary": "Cập nhật cấu hình email",
        "operationId": "update_email_config",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "description": "is_active=true khi còn người nhận chưa xác minh trả 422 với detail recipients_unverified.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "minProperties": 1,
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255
                  },
                  "recipients": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 10,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "format": "email"
                    }
                  },
                  "events": {
                    "type": "array",
                    "minItems": 1,
                    "contains": {
                      "const": "TRANSACTION_IN"
                    },
                    "items": {
                      "type": "string",
                      "enum": [
                        "TRANSACTION_IN",
                        "WEBHOOK_FAILED",
                        "VA_CREATED"
                      ]
                    }
                  },
                  "virtual_account_id": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "is_active": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envelope với data là EmailConfig.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/EmailConfig"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "detail=recipients_unverified hoặc dữ liệu không hợp lệ."
          }
        }
      },
      "delete": {
        "tags": [
          "Email"
        ],
        "summary": "Xoá thật cấu hình email",
        "operationId": "delete_email_config",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Đã xoá cấu hình.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Không tìm thấy cấu hình thuộc client."
          }
        }
      }
    },
    "/api/v1/email-configs/{id}/verify": {
      "post": {
        "tags": [
          "Email"
        ],
        "summary": "Xác minh người nhận email",
        "operationId": "verify_email_recipient",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "description": "Mã 6 số hết hạn sau 15 phút, tối đa 5 lần nhập sai. Khi mọi địa chỉ đã xác minh, hệ thống tự bật cấu hình.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "code"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "code": {
                    "type": "string",
                    "pattern": "^[0-9]{6}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envelope với data là EmailConfig.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/EmailConfig"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Mã sai, hết hạn hoặc đã vượt 5 lần nhập sai."
          }
        }
      }
    },
    "/api/v1/email-configs/{id}/resend-verification": {
      "post": {
        "tags": [
          "Email"
        ],
        "summary": "Gửi lại mã xác minh email",
        "operationId": "resend_email_verification",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "description": "Giới hạn 5 lần mỗi địa chỉ mỗi giờ và 30 lần mỗi client mỗi giờ.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Đã gửi mã mới nếu địa chỉ cần xác minh.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Vượt rate limit xác minh."
          }
        }
      }
    },
    "/api/v1/email-configs/{id}/test": {
      "post": {
        "tags": [
          "Email"
        ],
        "summary": "Gửi thử email tiền vào",
        "operationId": "test_email_config",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "description": "Gửi mẫu TRANSACTION_IN tới người nhận đã xác minh. Giới hạn 20 mail mỗi client mỗi giờ.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "maxProperties": 0
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "data: {sent: string[], skipped: [{email, reason}], log_ids: []}",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Vượt giới hạn mail test."
          }
        }
      }
    },
    "/api/v1/email-logs": {
      "get": {
        "tags": [
          "Email"
        ],
        "summary": "Log gửi email",
        "operationId": "list_email_logs",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "Chỉ trả metadata; không lưu hoặc trả nội dung email.",
        "parameters": [
          {
            "name": "config_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sent",
                "failed",
                "suppressed"
              ]
            }
          },
          {
            "name": "event_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "TRANSACTION_IN",
                "WEBHOOK_FAILED",
                "VA_CREATED",
                "VERIFICATION",
                "TEST",
                "RECEIPT"
              ]
            }
          },
          {
            "name": "from_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Log phân trang.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "page",
                        "limit",
                        "total"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/EmailLog"
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/email-logs/stats": {
      "get": {
        "tags": [
          "Email"
        ],
        "summary": "Thống kê gửi email",
        "operationId": "get_email_log_stats",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "from_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "data: {total, sent, failed, suppressed, success_rate, p95_duration_ms, error_labels: {label: n}}",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/email-suppressions": {
      "get": {
        "tags": [
          "Email"
        ],
        "summary": "Danh sách địa chỉ email bị chặn",
        "description": "Chỉ trả địa chỉ thuộc các cấu hình của client hiện tại.",
        "operationId": "list_email_suppressions",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Danh sách suppression gồm email, reason và thời điểm tạo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/email-suppressions/{email}": {
      "delete": {
        "tags": [
          "Email"
        ],
        "summary": "Gỡ chặn địa chỉ email",
        "operationId": "delete_email_suppression",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Client tự chịu trách nhiệm gỡ chặn sau khi sửa nguyên nhân; percent-encode địa chỉ trong URL khi cần.",
        "parameters": [
          {
            "name": "email",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "email"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Đã gỡ chặn địa chỉ.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Địa chỉ không bị chặn hoặc không thuộc client."
          }
        }
      }
    },
    "/api/v1/zalo-groups": {
      "get": {
        "tags": [
          "Zalo Groups"
        ],
        "summary": "Danh sách nhóm Zalo",
        "operationId": "list_zalo_groups",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope với data là danh sách cấu hình.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ZaloGroup"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Zalo Groups"
        ],
        "summary": "Nối nhóm Zalo",
        "operationId": "create_zalo_group",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Nhóm phải có bot Gấu Mona. Zalo chỉ nhận text thuần và không phân tích Markdown.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZaloGroupCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Envelope với data là cấu hình nhóm Zalo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ZaloGroup"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "group_id không phải chuỗi 10 đến 25 chữ số hoặc body không hợp lệ."
          },
          "503": {
            "description": "Kênh Zalo chưa mở trên máy chủ."
          }
        }
      }
    },
    "/api/v1/zalo-groups/{id}": {
      "put": {
        "tags": [
          "Zalo Groups"
        ],
        "summary": "Cập nhật nhóm Zalo",
        "operationId": "update_zalo_group",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID cấu hình nhóm Zalo, không phải group_id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZaloGroupUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Envelope với data là cấu hình nhóm Zalo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ZaloGroup"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Không tìm thấy cấu hình thuộc client."
          },
          "422": {
            "description": "Dữ liệu không hợp lệ."
          }
        }
      },
      "delete": {
        "tags": [
          "Zalo Groups"
        ],
        "summary": "Xoá nhóm Zalo",
        "operationId": "delete_zalo_group",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID cấu hình nhóm Zalo, không phải group_id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Đã xoá cấu hình nhóm Zalo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Không tìm thấy cấu hình thuộc client."
          }
        }
      }
    },
    "/api/v1/zalo-groups/{id}/test": {
      "post": {
        "tags": [
          "Zalo Groups"
        ],
        "summary": "Gửi thử vào nhóm Zalo",
        "operationId": "test_zalo_group",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID cấu hình nhóm Zalo, không phải group_id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Gửi tin “🐼 MONA Pay đã nối nhóm này…”; nhóm phải có bot Gấu Mona.",
        "responses": {
          "200": {
            "description": "Kết quả relay trong data.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/ZaloGroupTestResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Không tìm thấy cấu hình thuộc client."
          }
        }
      }
    },
    "/api/v1/zalo-groups/logs": {
      "get": {
        "tags": [
          "Zalo Groups"
        ],
        "summary": "Log gửi nhóm Zalo",
        "operationId": "zalo_group_logs",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 20
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ok",
                "failed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope với data là danh sách log gửi Zalo.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ZaloGroupLog"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sandbox/transactions": {
      "post": {
        "tags": [
          "Sandbox"
        ],
        "summary": "Tạo giao dịch tiền vào giả",
        "operationId": "create_sandbox_transaction",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Chạy được trước khi nối ngân hàng: MONA Pay tự tạo hoặc dùng lại VA sandbox SBX. Nếu truyền VA thật đã nối thì dùng VA đó. Giao dịch đi qua webhook, Telegram, email và checkout matcher nhưng không chuyển tiền thật, không tính hạn mức.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SandboxTransactionCreate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Giao dịch sandbox đã được chấp nhận để xử lý.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/SandboxTransaction"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Bearer token không hợp lệ hoặc hết hạn."
          },
          "403": {
            "description": "Thiếu hoặc sai X-Client-Secret."
          },
          "422": {
            "description": "Body không hợp lệ hoặc tài khoản được chỉ định không thuộc client."
          }
        }
      }
    },
    "/api/v1/payment-profile": {
      "get": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Hồ sơ trang thanh toán",
        "operationId": "get_payment_profile",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Hồ sơ của client.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PaymentProfile"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Chưa có hồ sơ thanh toán."
          }
        }
      },
      "put": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Tạo hoặc cập nhật hồ sơ trang thanh toán",
        "operationId": "set_payment_profile",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Kiểm tra tài khoản ngân hàng và VA thuộc client. return_signature_secret chỉ được trả một lần khi tạo mới.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentProfile"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Hồ sơ đã lưu.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/PaymentProfile"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "VA hoặc dữ liệu hồ sơ không hợp lệ."
          }
        }
      }
    },
    "/api/v1/payment-profile/reveal-return-secret": {
      "post": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Xem lại secret ký redirect",
        "operationId": "reveal_checkout_return_secret",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Xác nhận chủ tài khoản bằng password hoặc totp_code rồi trả return_signature_secret.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "minProperties": 1,
                "properties": {
                  "password": {
                    "type": "string",
                    "minLength": 1
                  },
                  "totp_code": {
                    "type": "string",
                    "pattern": "^[0-9]{6}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Secret hiện tại.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "return_signature_secret"
                      ],
                      "properties": {
                        "return_signature_secret": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Xác nhận mật khẩu hoặc 2FA không đúng."
          },
          "404": {
            "description": "Chưa có hồ sơ thanh toán."
          }
        }
      }
    },
    "/api/v1/payment-profile/rotate-return-secret": {
      "post": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Xoay secret ký redirect",
        "operationId": "rotate_checkout_return_secret",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "responses": {
          "200": {
            "description": "Secret mới, chỉ trả một lần.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "return_signature_secret"
                      ],
                      "properties": {
                        "return_signature_secret": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/checkouts": {
      "get": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Danh sách phiên thanh toán",
        "operationId": "list_checkouts",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "paid",
                "expired",
                "cancelled"
              ]
            }
          },
          {
            "name": "order_code",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 50
            }
          },
          {
            "name": "from_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to_date",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Danh sách checkout phân trang.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "items",
                        "page",
                        "limit",
                        "total"
                      ],
                      "properties": {
                        "items": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Checkout"
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "total": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Tạo phiên thanh toán và link thu tiền",
        "operationId": "create_checkout",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Tạo VietQR động và trả checkout_url. Nếu chưa có hồ sơ trả 422 detail=payment_profile_missing.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Envelope với data là Checkout.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Trùng order_code đang pending hoặc Idempotency-Key khác body."
          },
          "422": {
            "description": "payment_profile_missing hoặc dữ liệu không hợp lệ."
          },
          "502": {
            "description": "Ngân hàng không tạo được QR."
          }
        }
      }
    },
    "/api/v1/checkouts/{id}": {
      "get": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Chi tiết phiên thanh toán",
        "operationId": "get_checkout",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope với data là Checkout.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Không tìm thấy checkout thuộc client."
          }
        }
      }
    },
    "/api/v1/checkouts/{id}/cancel": {
      "post": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Huỷ phiên đang chờ",
        "operationId": "cancel_checkout",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope với data là Checkout.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Không tìm thấy checkout."
          },
          "409": {
            "description": "Checkout không còn ở trạng thái pending."
          }
        }
      }
    },
    "/api/v1/checkouts/{id}/expire-now": {
      "post": {
        "tags": [
          "Hosted checkout"
        ],
        "summary": "Cho phiên hết hạn ngay",
        "operationId": "expire_checkout_now",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "description": "Chỉ dành cho admin hoặc test.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "TTL 24 giờ; cùng key khác body trả 409."
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope với data là Checkout.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Checkout không còn pending."
          }
        }
      }
    },
    "/api/v1/checkouts/public/{token}": {
      "get": {
        "tags": [
          "Hosted checkout public"
        ],
        "summary": "Dữ liệu trang thanh toán public",
        "operationId": "get_public_checkout",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tên shop, logo, hotline, accent, số tiền, mã đơn, ngân hàng, QR, trạng thái, hạn và URL trở về. Không lộ client_id, id nội bộ hoặc email.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token không tồn tại."
          },
          "429": {
            "description": "Quá 60 request mỗi phút trên IP."
          }
        }
      }
    },
    "/api/v1/checkouts/public/{token}/status": {
      "get": {
        "tags": [
          "Hosted checkout public"
        ],
        "summary": "Poll trạng thái checkout",
        "operationId": "get_public_checkout_status",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trạng thái gọn để poll mỗi 3 giây.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "required": [
                        "status",
                        "expires_at",
                        "seconds_left"
                      ],
                      "properties": {
                        "status": {
                          "type": "string",
                          "enum": [
                            "pending",
                            "paid",
                            "expired",
                            "cancelled"
                          ]
                        },
                        "paid_at": {
                          "anyOf": [
                            {
                              "type": "string",
                              "format": "date-time"
                            },
                            {
                              "type": "null"
                            }
                          ]
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "seconds_left": {
                          "type": "integer",
                          "minimum": 0
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token không tồn tại."
          },
          "429": {
            "description": "Quá 60 request mỗi phút trên IP."
          }
        }
      }
    },
    "/api/v1/checkouts/public/{token}/qr.png": {
      "get": {
        "tags": [
          "Hosted checkout public"
        ],
        "summary": "Ảnh QR của checkout",
        "operationId": "get_public_checkout_qr_image",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 32
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 128,
              "maximum": 2048,
              "default": 512
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ảnh QR PNG hiển thị inline.",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "inline"
              }
            },
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "Token không tồn tại."
          }
        }
      }
    },
    "/api/v1/checkouts/public/{token}/cancel": {
      "post": {
        "tags": [
          "Hosted checkout public"
        ],
        "summary": "Khách huỷ checkout đang chờ",
        "operationId": "cancel_public_checkout",
        "security": [],
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 32
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Checkout cancelled và cancel_url để chuyển về merchant.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {}
                  }
                }
              }
            }
          },
          "404": {
            "description": "Token không tồn tại."
          },
          "409": {
            "description": "Checkout không còn pending."
          },
          "429": {
            "description": "Quá 60 request mỗi phút trên IP."
          }
        }
      }
    },
    "/api/v1/qr/{qr_id}/image.png": {
      "get": {
        "tags": [
          "QR public"
        ],
        "summary": "Ảnh PNG cho QR đã tạo",
        "operationId": "get_qr_image",
        "security": [],
        "parameters": [
          {
            "name": "qr_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 128,
              "maximum": 2048,
              "default": 512
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ảnh QR PNG hiển thị inline.",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "inline"
              }
            },
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "QR không tồn tại."
          }
        }
      }
    },
    "/api/v1/qr/generate": {
      "post": {
        "tags": [
          "QR"
        ],
        "summary": "Tạo QR thanh toán",
        "operationId": "generate_qr",
        "security": [
          {
            "bearerAuth": [],
            "clientSecret": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "description": "Thông tin ngân hàng, số tiền và nội dung theo cấu hình QR của client."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kết quả tạo QR, có qr_image_url trỏ tới ảnh PNG public.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "message",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "message": {
                      "type": "string"
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "required": [
                        "qr_image_url"
                      ],
                      "properties": {
                        "qr_image_url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Ảnh PNG public của QR."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AdditionalInfo": {
        "properties": {
          "key": {
            "type": "string",
            "minLength": 1,
            "title": "Key",
            "description": "Key for additional information"
          },
          "value": {
            "type": "string",
            "minLength": 1,
            "title": "Value",
            "description": "Value for additional information"
          }
        },
        "type": "object",
        "required": [
          "key",
          "value"
        ],
        "title": "AdditionalInfo"
      },
      "Body_notification_verification_api_v1_acb__acb_request_id__notification_verification_post": {
        "properties": {
          "code": {
            "type": "string",
            "title": "Code"
          }
        },
        "type": "object",
        "required": [
          "code"
        ],
        "title": "Body_notification_verification_api_v1_acb__acb_request_id__notification_verification_post"
      },
      "Body_reset_client_password_api_v1_client__client_id__reset_password_put": {
        "properties": {
          "password": {
            "type": "string",
            "title": "Password"
          }
        },
        "type": "object",
        "required": [
          "password"
        ],
        "title": "Body_reset_client_password_api_v1_client__client_id__reset_password_put"
      },
      "Body_update_status_api_v1_client__client_id__status_put": {
        "properties": {
          "is_active": {
            "type": "boolean",
            "title": "Is Active"
          }
        },
        "type": "object",
        "required": [
          "is_active"
        ],
        "title": "Body_update_status_api_v1_client__client_id__status_put"
      },
      "Body_virtual_account_verification_api_v1_acb__acb_request_id__virtual_account_verification_post": {
        "properties": {
          "code": {
            "type": "string",
            "title": "Code"
          }
        },
        "type": "object",
        "required": [
          "code"
        ],
        "title": "Body_virtual_account_verification_api_v1_acb__acb_request_id__virtual_account_verification_post"
      },
      "ChangePasswordRequest": {
        "properties": {
          "old_password": {
            "type": "string",
            "minLength": 1,
            "title": "Old Password"
          },
          "new_password": {
            "type": "string",
            "minLength": 1,
            "title": "New Password"
          }
        },
        "type": "object",
        "required": [
          "old_password",
          "new_password"
        ],
        "title": "ChangePasswordRequest"
      },
      "ClientCreate": {
        "properties": {
          "username": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Username",
            "description": "Client username is required"
          },
          "password": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Password",
            "description": "Client password is required"
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Name",
            "description": "Client name is required"
          }
        },
        "type": "object",
        "required": [
          "username",
          "password",
          "name"
        ],
        "title": "ClientCreate"
      },
      "ClientServiceCodeBody": {
        "properties": {
          "service_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Service Code",
            "description": "lms/rmp/...; null để bỏ map service."
          }
        },
        "type": "object",
        "title": "ClientServiceCodeBody"
      },
      "ClientWebhookBaseUrlBody": {
        "properties": {
          "webhook_base_url": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048
              },
              {
                "type": "null"
              }
            ],
            "title": "Webhook Base Url",
            "description": "Ví dụ https://lms.example.com — không gồm path rtxn-ipn-callback / qr-ipn-callback"
          }
        },
        "type": "object",
        "title": "ClientWebhookBaseUrlBody",
        "description": "Để trống hoặc null = xóa cấu hình, webhook dùng WEB_HOOK_MONA_URL (env)."
      },
      "DebitCreditLower": {
        "type": "string",
        "enum": [
          "debit",
          "credit"
        ],
        "title": "DebitCreditLower"
      },
      "GenerateKeyRequest": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "default": "Default Key"
          }
        },
        "type": "object",
        "title": "GenerateKeyRequest"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "LoginRequest": {
        "properties": {
          "username": {
            "type": "string",
            "title": "Username"
          },
          "password": {
            "type": "string",
            "title": "Password"
          }
        },
        "type": "object",
        "required": [
          "username",
          "password"
        ],
        "title": "LoginRequest"
      },
      "MasterMeta": {
        "properties": {
          "clientId": {
            "type": "string",
            "format": "uuid",
            "title": "Clientid"
          },
          "clientRequestId": {
            "type": "string",
            "format": "uuid",
            "title": "Clientrequestid"
          },
          "checksum": {
            "type": "string",
            "title": "Checksum"
          }
        },
        "type": "object",
        "required": [
          "clientId",
          "clientRequestId",
          "checksum"
        ],
        "title": "MasterMeta"
      },
      "NotificationRegistrationRequest": {
        "properties": {
          "username": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 50
              },
              {
                "type": "null"
              }
            ],
            "title": "Username",
            "description": "Thông tin đăng nhập"
          },
          "receive_noti_realtime": {
            "type": "boolean",
            "title": "Receive Noti Realtime",
            "description": "Nhận thông báo tức thì hoặc nhận thông báo cuối ngày"
          }
        },
        "type": "object",
        "required": [
          "receive_noti_realtime"
        ],
        "title": "NotificationRegistrationRequest"
      },
      "Pagination": {
        "properties": {
          "page": {
            "type": "integer",
            "minimum": 1,
            "title": "Page"
          },
          "pageSize": {
            "type": "integer",
            "maximum": 1000,
            "minimum": 1,
            "title": "Pagesize"
          },
          "totalPage": {
            "type": "integer",
            "minimum": 1,
            "title": "Totalpage"
          }
        },
        "type": "object",
        "required": [
          "page",
          "pageSize",
          "totalPage"
        ],
        "title": "Pagination"
      },
      "PartnerWebhookConfigCreate": {
        "properties": {
          "service_code": {
            "type": "string",
            "maxLength": 50,
            "minLength": 1,
            "title": "Service Code"
          },
          "base_url": {
            "type": "string",
            "maxLength": 2048,
            "minLength": 1,
            "title": "Base Url"
          },
          "auth_header_name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Auth Header Name",
            "default": "X-Webhook-Key"
          },
          "auth_secret": {
            "type": "string",
            "maxLength": 512,
            "minLength": 1,
            "title": "Auth Secret"
          },
          "is_active": {
            "type": "boolean",
            "title": "Is Active",
            "default": true
          }
        },
        "type": "object",
        "required": [
          "service_code",
          "base_url",
          "auth_secret"
        ],
        "title": "PartnerWebhookConfigCreate"
      },
      "PartnerWebhookConfigUpdate": {
        "properties": {
          "base_url": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048
              },
              {
                "type": "null"
              }
            ],
            "title": "Base Url"
          },
          "auth_header_name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Auth Header Name"
          },
          "auth_secret": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 512
              },
              {
                "type": "null"
              }
            ],
            "title": "Auth Secret"
          },
          "is_active": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Active"
          }
        },
        "type": "object",
        "title": "PartnerWebhookConfigUpdate"
      },
      "QRCancelRequest": {
        "properties": {
          "ownerNumber": {
            "type": "string",
            "title": "Ownernumber",
            "description": "Owner Number"
          },
          "ownerType": {
            "$ref": "#/components/schemas/QRCustomerTypeEnum",
            "description": "Owner Type"
          },
          "traceNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tracenumber",
            "description": "Unique identifier for the transaction"
          },
          "orderId": {
            "type": "string",
            "minLength": 1,
            "title": "Orderid",
            "description": "Order identifier"
          },
          "amount": {
            "type": "integer",
            "maximum": 1000000000,
            "minimum": 0,
            "title": "Amount",
            "description": "Transaction amount (min: 0, max: 1,000,000,000)"
          }
        },
        "type": "object",
        "required": [
          "ownerNumber",
          "ownerType",
          "orderId",
          "amount"
        ],
        "title": "QRCancelRequest",
        "example": {
          "amount": 1234567,
          "orderId": "123abc123abc",
          "ownerNumber": "1234567890",
          "ownerType": "PER",
          "traceNumber": "0ca0f0c0-5177-4588-807f-e5f3dccd2551"
        }
      },
      "QRCustomerTypeEnum": {
        "type": "string",
        "enum": [
          "PER",
          "ORG"
        ],
        "title": "QRCustomerTypeEnum"
      },
      "QRPaymentRequest": {
        "properties": {
          "ownerNumber": {
            "type": "string",
            "title": "Ownernumber",
            "description": "Owner Number"
          },
          "ownerType": {
            "$ref": "#/components/schemas/QRCustomerTypeEnum",
            "description": "Owner Type"
          },
          "traceNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tracenumber",
            "description": "Unique identifier for the transaction"
          },
          "merchantId": {
            "type": "string",
            "minLength": 1,
            "title": "Merchantid",
            "description": "Merchant identifier"
          },
          "terminalId": {
            "type": "string",
            "minLength": 1,
            "title": "Terminalid",
            "description": "Terminal identifier"
          },
          "userId": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Userid",
            "description": "User identifier"
          },
          "orderId": {
            "type": "string",
            "minLength": 1,
            "title": "Orderid",
            "description": "Order identifier"
          },
          "virtualAccountPrefix": {
            "type": "string",
            "maxLength": 10,
            "minLength": 1,
            "title": "Virtualaccountprefix",
            "description": "Virtual account prefix"
          },
          "beneficiaryName": {
            "type": "string",
            "maxLength": 100,
            "minLength": 1,
            "title": "Beneficiaryname",
            "description": "Name of the beneficiary"
          },
          "amount": {
            "type": "integer",
            "maximum": 1000000000,
            "minimum": 0,
            "title": "Amount",
            "description": "Transaction amount (min: 0, max: 1,000,000,000)"
          },
          "voucherCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vouchercode",
            "description": "Voucher code"
          },
          "loyaltyCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Loyaltycode",
            "description": "Loyalty program code"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255,
                "minLength": 0
              },
              {
                "type": "null"
              }
            ],
            "title": "Description",
            "description": "Transaction description"
          },
          "additionalInfo": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/AdditionalInfo"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Additionalinfo",
            "description": "Additional information as key-value pairs"
          },
          "payer_email": {
            "anyOf": [
              {
                "type": "string",
                "format": "email"
              },
              {
                "type": "null"
              }
            ],
            "description": "Tuỳ chọn. Gửi biên lai Đã nhận thanh toán khi giao dịch khớp QR."
          }
        },
        "type": "object",
        "required": [
          "ownerNumber",
          "ownerType",
          "merchantId",
          "terminalId",
          "orderId",
          "virtualAccountPrefix",
          "beneficiaryName",
          "amount"
        ],
        "title": "QRPaymentRequest",
        "example": {
          "additionalInfo": [
            {
              "key": "key",
              "value": "value"
            }
          ],
          "amount": 1234567,
          "beneficiaryName": "ADAM 34682",
          "description": "hoa don thanh toan",
          "loyaltyCode": "123abc123abc",
          "merchantId": "123abc123abc",
          "orderId": "123abc123abc",
          "ownerNumber": "1234567890",
          "ownerType": "PER",
          "terminalId": "123abc123abc",
          "traceNumber": "0ca0f0c0-5177-4588-807f-e5f3dccd2551",
          "userId": "acb34682",
          "virtualAccountPrefix": "HAB",
          "voucherCode": "123abc123abc",
          "payer_email": "payer@example.com"
        }
      },
      "QrRootRequest": {
        "properties": {
          "requestTrace": {
            "type": "string",
            "title": "Requesttrace"
          },
          "requestDateTime": {
            "type": "string",
            "format": "date-time",
            "title": "Requestdatetime"
          },
          "requestParameters": {
            "$ref": "#/components/schemas/RequestParameters"
          }
        },
        "type": "object",
        "required": [
          "requestTrace",
          "requestDateTime",
          "requestParameters"
        ],
        "title": "QrRootRequest"
      },
      "RequestCode": {
        "type": "string",
        "enum": [
          "TRANSACTION_UPDATE",
          "TRANSACTION_HISTORY"
        ],
        "title": "RequestCode"
      },
      "RequestMeta": {
        "properties": {
          "requestType": {
            "$ref": "#/components/schemas/RequestType"
          },
          "requestCode": {
            "$ref": "#/components/schemas/RequestCode"
          }
        },
        "type": "object",
        "required": [
          "requestType",
          "requestCode"
        ],
        "title": "RequestMeta"
      },
      "RequestParameters": {
        "properties": {
          "masterMeta": {
            "$ref": "#/components/schemas/MasterMeta"
          },
          "request": {
            "$ref": "#/components/schemas/src__schemas__requests__qr_callback_request__Request"
          }
        },
        "type": "object",
        "required": [
          "masterMeta",
          "request"
        ],
        "title": "RequestParameters"
      },
      "RequestType": {
        "type": "string",
        "enum": [
          "NOTIFICATION",
          "QUERY"
        ],
        "title": "RequestType"
      },
      "Response": {
        "properties": {
          "success": {
            "type": "boolean",
            "title": "Success"
          },
          "message": {
            "type": "string",
            "title": "Message"
          },
          "data": {
            "anyOf": [
              {},
              {
                "type": "null"
              }
            ],
            "title": "Data"
          }
        },
        "type": "object",
        "required": [
          "success",
          "message"
        ],
        "title": "Response"
      },
      "RtxnRootRequest": {
        "properties": {
          "masterMeta": {
            "$ref": "#/components/schemas/MasterMeta"
          },
          "requests": {
            "$ref": "#/components/schemas/src__schemas__requests__rtxn_callback_request__Request"
          },
          "request_trace": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Request Trace"
          }
        },
        "type": "object",
        "required": [
          "masterMeta",
          "requests"
        ],
        "title": "RtxnRootRequest"
      },
      "TransactionChannel": {
        "type": "string",
        "enum": [
          "MAPP",
          "WEB",
          "ATM",
          "IBFT",
          "API",
          "BAT",
          "VRU",
          "WWW",
          "ONLI",
          "ACH",
          "FSC",
          "CCM",
          "MG",
          "SECU",
          "SMS",
          "ACHS",
          "CCAT",
          "AAP",
          "CLMS",
          "REMI",
          "TB",
          "SOBA",
          "BIZ"
        ],
        "title": "TransactionChannel"
      },
      "TransactionEntityAttribute": {
        "properties": {
          "traceNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tracenumber"
          },
          "beneficiaryName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Beneficiaryname"
          },
          "beneficiaryAccountNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Beneficiaryaccountnumber"
          },
          "receiverBankName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Receiverbankname"
          },
          "remitterName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Remittername"
          },
          "remitterAccountNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Remitteraccountnumber"
          },
          "issuerBankName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Issuerbankname"
          },
          "virtualAccount": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Virtualaccount"
          },
          "referenceNumber": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Referencenumber"
          },
          "partnerCustomerCode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Partnercustomercode"
          },
          "partnerCustomerName": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Partnercustomername"
          },
          "partnerCustomerType": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Partnercustomertype"
          },
          "custom1": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom1"
          },
          "custom2": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom2"
          },
          "custom3": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom3"
          },
          "custom4": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom4"
          },
          "custom5": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom5"
          },
          "custom6": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom6"
          },
          "custom7": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom7"
          },
          "custom8": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom8"
          },
          "custom9": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom9"
          },
          "custom10": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custom10"
          }
        },
        "type": "object",
        "title": "TransactionEntityAttribute"
      },
      "TransactionStatus": {
        "type": "string",
        "enum": [
          "COMPLETED",
          "PENDING",
          "FAILED",
          "ERRORCORRECTED"
        ],
        "title": "TransactionStatus"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "VirtualAccount": {
        "properties": {
          "vaPrefixCd": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vaprefixcd"
          },
          "vaNbr": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Vanbr"
          }
        },
        "type": "object",
        "title": "VirtualAccount"
      },
      "VirtualAccountInfo": {
        "properties": {
          "virtual_account_prefix_code": {
            "type": "string",
            "title": "Virtual Account Prefix Code",
            "description": "Đầu số tài khoản định danh"
          },
          "virtual_account_content": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Virtual Account Content",
            "description": "Nội dung tài khoản định danh"
          },
          "virtual_account_explain": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Virtual Account Explain",
            "description": "Nội dung diễn giải khi đăng ký"
          },
          "beneficiary_name_rule": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Beneficiary Name Rule",
            "description": "Loại hiển thị tên đơn vị hưởng"
          }
        },
        "type": "object",
        "required": [
          "virtual_account_prefix_code"
        ],
        "title": "VirtualAccountInfo"
      },
      "VirtualAccountRegistrationRequest": {
        "properties": {
          "bank_account_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bank Account Id",
            "description": "ID bank_account có sẵn (ưu tiên dùng khi chọn từ danh sách)"
          },
          "customer_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customer Type",
            "description": "Loại khách hàng (ví dụ: PERS)"
          },
          "account_number": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Account Number",
            "description": "Số tài khoản thanh toán chính"
          },
          "phone_number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone Number",
            "description": "Số điện thoại khách hàng"
          },
          "virtual_account_info": {
            "$ref": "#/components/schemas/VirtualAccountInfo"
          },
          "user_agreement": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "User Agreement",
            "description": "Sự đồng ý của KH khi đăng ký dịch vụ"
          }
        },
        "type": "object",
        "required": [
          "virtual_account_info"
        ],
        "title": "VirtualAccountRegistrationRequest"
      },
      "src__schemas__requests__qr_callback_request__Request": {
        "properties": {
          "requestMeta": {
            "$ref": "#/components/schemas/RequestMeta"
          },
          "requestParams": {
            "$ref": "#/components/schemas/src__schemas__requests__qr_callback_request__RequestParams"
          }
        },
        "type": "object",
        "required": [
          "requestMeta",
          "requestParams"
        ],
        "title": "Request"
      },
      "src__schemas__requests__qr_callback_request__RequestParams": {
        "properties": {
          "transactions": {
            "items": {
              "$ref": "#/components/schemas/src__schemas__requests__qr_callback_request__Transaction"
            },
            "type": "array",
            "title": "Transactions"
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "type": "object",
        "required": [
          "transactions",
          "pagination"
        ],
        "title": "RequestParams"
      },
      "src__schemas__requests__qr_callback_request__Transaction": {
        "properties": {
          "transactionStatus": {
            "$ref": "#/components/schemas/TransactionStatus"
          },
          "transactionChannel": {
            "$ref": "#/components/schemas/TransactionChannel"
          },
          "transactionDate": {
            "type": "string",
            "format": "date-time",
            "title": "Transactiondate"
          },
          "effectiveDate": {
            "type": "string",
            "format": "date-time",
            "title": "Effectivedate"
          },
          "debitOrCredit": {
            "$ref": "#/components/schemas/DebitCreditLower"
          },
          "amount": {
            "type": "integer",
            "title": "Amount"
          },
          "transactionEntityAttribute": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TransactionEntityAttribute"
              },
              {
                "type": "null"
              }
            ]
          },
          "transactionContent": {
            "type": "string",
            "title": "Transactioncontent"
          }
        },
        "type": "object",
        "required": [
          "transactionStatus",
          "transactionChannel",
          "transactionDate",
          "effectiveDate",
          "debitOrCredit",
          "amount",
          "transactionContent"
        ],
        "title": "Transaction"
      },
      "src__schemas__requests__rtxn_callback_request__Request": {
        "properties": {
          "requestMeta": {
            "$ref": "#/components/schemas/RequestMeta"
          },
          "requestParams": {
            "$ref": "#/components/schemas/src__schemas__requests__rtxn_callback_request__RequestParams"
          }
        },
        "type": "object",
        "required": [
          "requestMeta",
          "requestParams"
        ],
        "title": "Request"
      },
      "src__schemas__requests__rtxn_callback_request__RequestParams": {
        "properties": {
          "transactions": {
            "items": {
              "$ref": "#/components/schemas/src__schemas__requests__rtxn_callback_request__Transaction"
            },
            "type": "array",
            "title": "Transactions"
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        },
        "type": "object",
        "required": [
          "transactions",
          "pagination"
        ],
        "title": "RequestParams"
      },
      "src__schemas__requests__rtxn_callback_request__Transaction": {
        "properties": {
          "transactionStatus": {
            "$ref": "#/components/schemas/TransactionStatus"
          },
          "transactionChannel": {
            "$ref": "#/components/schemas/TransactionChannel"
          },
          "transactionCode": {
            "type": "string",
            "title": "Transactioncode"
          },
          "accountNumber": {
            "type": "string",
            "title": "Accountnumber"
          },
          "transactionDate": {
            "type": "string",
            "format": "date-time",
            "title": "Transactiondate"
          },
          "effectiveDate": {
            "type": "string",
            "format": "date-time",
            "title": "Effectivedate"
          },
          "debitOrCredit": {
            "$ref": "#/components/schemas/DebitCreditLower"
          },
          "virtualAccount": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/VirtualAccount"
              },
              {
                "type": "null"
              }
            ]
          },
          "amount": {
            "type": "integer",
            "title": "Amount"
          },
          "transactionEntityAttribute": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/TransactionEntityAttribute"
              },
              {
                "type": "null"
              }
            ]
          },
          "transactionContent": {
            "type": "string",
            "title": "Transactioncontent"
          }
        },
        "type": "object",
        "required": [
          "transactionStatus",
          "transactionChannel",
          "transactionCode",
          "accountNumber",
          "transactionDate",
          "effectiveDate",
          "debitOrCredit",
          "amount",
          "transactionContent"
        ],
        "title": "Transaction"
      },
      "EmailConfig": {
        "type": "object",
        "title": "EmailConfig",
        "description": "Cấu hình thông báo email. Chỉ hoạt động khi mọi người nhận đã xác minh và is_active=true.",
        "required": [
          "id",
          "client_id",
          "name",
          "recipients",
          "recipient_status",
          "events",
          "is_active",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "client_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "recipients": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "recipient_status": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "email",
                "verified",
                "suppressed"
              ],
              "properties": {
                "email": {
                  "type": "string",
                  "format": "email"
                },
                "verified": {
                  "type": "boolean"
                },
                "suppressed": {
                  "type": "boolean"
                }
              }
            }
          },
          "pending_verification": {
            "type": "array",
            "description": "Các địa chỉ còn phải nhập mã 6 số.",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "TRANSACTION_IN",
                "WEBHOOK_FAILED",
                "VA_CREATED"
              ]
            }
          },
          "virtual_account_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "EmailConfigCreate": {
        "type": "object",
        "title": "EmailConfigCreate",
        "required": [
          "name",
          "recipients"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "recipients": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "default": [
              "TRANSACTION_IN"
            ],
            "contains": {
              "const": "TRANSACTION_IN"
            },
            "items": {
              "type": "string",
              "enum": [
                "TRANSACTION_IN",
                "WEBHOOK_FAILED",
                "VA_CREATED"
              ]
            }
          },
          "virtual_account_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "example": {
          "name": "Ke toan",
          "recipients": [
            "ketoan@example.com"
          ],
          "events": [
            "TRANSACTION_IN",
            "WEBHOOK_FAILED"
          ]
        }
      },
      "EmailLog": {
        "type": "object",
        "title": "EmailLog",
        "description": "Metadata của một lần gửi. Hệ thống không lưu nội dung email.",
        "required": [
          "id",
          "client_id",
          "event_type",
          "recipient",
          "subject",
          "status",
          "error_label",
          "attempt",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "client_id": {
            "type": "string",
            "format": "uuid"
          },
          "config_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "event_type": {
            "type": "string",
            "enum": [
              "TRANSACTION_IN",
              "WEBHOOK_FAILED",
              "VA_CREATED",
              "VERIFICATION",
              "TEST",
              "RECEIPT"
            ]
          },
          "recipient": {
            "type": "string",
            "format": "email"
          },
          "subject": {
            "type": "string"
          },
          "message_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "sent",
              "failed",
              "suppressed",
              "skipped"
            ]
          },
          "smtp_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "duration_ms": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ]
          },
          "error_label": {
            "type": "string",
            "enum": [
              "OK",
              "SMTP_4XX",
              "SMTP_5XX",
              "TIMEOUT",
              "CONNECTION",
              "SUPPRESSED",
              "RATE_LIMITED",
              "TEMPLATE",
              "UNVERIFIED"
            ]
          },
          "attempt": {
            "type": "integer",
            "minimum": 1
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ZaloGroup": {
        "type": "object",
        "title": "ZaloGroup",
        "description": "Cấu hình gửi thông báo text thuần vào nhóm Zalo đã có bot Gấu Mona. target là group_id.",
        "required": [
          "id",
          "type",
          "target",
          "friendly_name",
          "virtual_account_id",
          "message_template",
          "is_active",
          "events",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "ID cấu hình nhóm Zalo."
          },
          "type": {
            "type": "string",
            "const": "zalo_group"
          },
          "target": {
            "type": "string",
            "pattern": "^[0-9]{10,25}$",
            "description": "group_id của nhóm Zalo."
          },
          "friendly_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "virtual_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Giới hạn theo VA; null để nhận mọi VA."
          },
          "message_template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Mẫu text thuần; hỗ trợ biến một hoặc hai cặp dấu ngoặc nhọn."
          },
          "is_active": {
            "type": "boolean"
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "TRANSACTION_IN",
                "CHECKOUT_PAID",
                "WEBHOOK_FAILED",
                "VA_CREATED"
              ]
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ZaloGroupCreate": {
        "type": "object",
        "title": "ZaloGroupCreate",
        "additionalProperties": false,
        "required": [
          "group_id",
          "friendly_name"
        ],
        "properties": {
          "group_id": {
            "type": "string",
            "pattern": "^[0-9]{10,25}$",
            "description": "ID nhóm Zalo gồm 10 đến 25 chữ số; nhóm phải có bot Gấu Mona."
          },
          "friendly_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "virtual_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "message_template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Text thuần vì Zalo không phân tích Markdown."
          },
          "is_active": {
            "type": "boolean",
            "default": true
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "default": [
              "TRANSACTION_IN"
            ],
            "items": {
              "type": "string",
              "enum": [
                "TRANSACTION_IN",
                "CHECKOUT_PAID",
                "WEBHOOK_FAILED",
                "VA_CREATED"
              ]
            }
          }
        },
        "example": {
          "group_id": "7119000000000000000",
          "friendly_name": "Nhom ban hang",
          "events": [
            "TRANSACTION_IN"
          ],
          "is_active": true
        }
      },
      "ZaloGroupUpdate": {
        "type": "object",
        "title": "ZaloGroupUpdate",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "group_id": {
            "type": "string",
            "pattern": "^[0-9]{10,25}$"
          },
          "friendly_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "virtual_account_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "message_template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "is_active": {
            "type": "boolean"
          },
          "events": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "TRANSACTION_IN",
                "CHECKOUT_PAID",
                "WEBHOOK_FAILED",
                "VA_CREATED"
              ]
            }
          }
        }
      },
      "ZaloGroupTestResult": {
        "type": "object",
        "title": "ZaloGroupTestResult",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "zalo_message_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Lý do relay thất bại và nhắc kiểm tra bot Gấu Mona."
          }
        }
      },
      "ZaloGroupLog": {
        "type": "object",
        "title": "ZaloGroupLog",
        "required": [
          "id",
          "event",
          "transaction_code",
          "group_id",
          "status",
          "error",
          "zalo_message_id",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "event": {
            "type": "string"
          },
          "transaction_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "group_id": {
            "type": "string",
            "pattern": "^[0-9]{10,25}$"
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "failed"
            ]
          },
          "error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "zalo_message_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SandboxTransactionCreate": {
        "type": "object",
        "title": "SandboxTransactionCreate",
        "required": [
          "amount",
          "description"
        ],
        "additionalProperties": false,
        "description": "Tạo giao dịch tiền vào giả. Bỏ trống số tài khoản để MONA Pay tự tạo hoặc dùng lại VA sandbox SBX của client.",
        "properties": {
          "virtual_account_number": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50,
            "description": "VA thật đã nối hoặc VA sandbox SBX; không bắt buộc."
          },
          "account_number": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50,
            "description": "Tài khoản thật đã nối; không bắt buộc."
          },
          "amount": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000000000,
            "description": "Số tiền giả, đơn vị VND."
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Nội dung chuyển khoản giả."
          },
          "transaction_code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "Mã tuỳ chọn để thử chống trùng; hệ thống tự sinh SANDBOX-… khi bỏ trống."
          }
        },
        "example": {
          "amount": 250000,
          "description": "Thanh toan DH10234",
          "transaction_code": "SANDBOX-DH10234-01"
        }
      },
      "SandboxTransaction": {
        "type": "object",
        "title": "SandboxTransaction",
        "required": [
          "transaction_code",
          "virtual_account_number",
          "account_number",
          "amount",
          "is_sandbox"
        ],
        "properties": {
          "transaction_code": {
            "type": "string"
          },
          "virtual_account_number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "VA chỉ định hoặc VA sandbox tự cấp, bắt đầu bằng SBX khi client chưa nối ngân hàng; null khi chỉ định tài khoản thật."
          },
          "account_number": {
            "type": "string"
          },
          "amount": {
            "type": "integer"
          },
          "is_sandbox": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "PaymentProfile": {
        "type": "object",
        "title": "PaymentProfile",
        "description": "Hồ sơ nhận diện và tài khoản mặc định cho hosted checkout. return_signature_secret chỉ được trả một lần khi tạo hoặc xoay.",
        "required": [
          "display_name",
          "default_bank_account_id",
          "va_prefix",
          "owner_number",
          "owner_type",
          "merchant_id",
          "terminal_id",
          "beneficiary_name",
          "locale",
          "show_mona_badge"
        ],
        "properties": {
          "display_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "logo_url": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri",
                "pattern": "^https://"
              },
              {
                "type": "null"
              }
            ],
            "description": "Logo HTTPS, tối đa 512 KB."
          },
          "hotline": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ]
          },
          "support_email": {
            "anyOf": [
              {
                "type": "string",
                "format": "email"
              },
              {
                "type": "null"
              }
            ]
          },
          "default_bank_account_id": {
            "type": "string",
            "format": "uuid"
          },
          "default_virtual_account_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ]
          },
          "va_prefix": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20
          },
          "owner_number": {
            "type": "string",
            "minLength": 1
          },
          "owner_type": {
            "type": "string",
            "enum": [
              "PER",
              "ORG"
            ]
          },
          "merchant_id": {
            "type": "string",
            "minLength": 1
          },
          "terminal_id": {
            "type": "string",
            "minLength": 1
          },
          "beneficiary_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255
          },
          "accent_color": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^#[0-9A-Fa-f]{6}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "locale": {
            "type": "string",
            "enum": [
              "vi",
              "en"
            ],
            "default": "vi"
          },
          "show_mona_badge": {
            "type": "boolean",
            "default": true
          },
          "return_signature_secret": {
            "type": "string",
            "readOnly": true,
            "description": "Secret 48 ký tự, chỉ có trong response tạo mới hoặc xoay secret."
          }
        }
      },
      "CheckoutCreate": {
        "type": "object",
        "title": "CheckoutCreate",
        "required": [
          "amount",
          "order_code",
          "return_url"
        ],
        "properties": {
          "amount": {
            "type": "integer",
            "minimum": 1000,
            "maximum": 1000000000,
            "description": "Số tiền VND."
          },
          "order_code": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50,
            "pattern": "^[A-Za-z0-9_-]+$"
          },
          "description": {
            "type": "string",
            "maxLength": 100
          },
          "return_url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://"
          },
          "cancel_url": {
            "type": "string",
            "format": "uri",
            "pattern": "^https://"
          },
          "payer_email": {
            "type": "string",
            "format": "email"
          },
          "payer_name": {
            "type": "string",
            "maxLength": 255
          },
          "expires_in": {
            "type": "integer",
            "minimum": 60,
            "maximum": 86400,
            "default": 900
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "JSON tối đa 2 KB sau khi encode."
          },
          "virtual_account_id": {
            "type": "string",
            "format": "uuid"
          },
          "sandbox": {
            "type": "boolean",
            "default": false,
            "description": "true để dùng VA sandbox SBX và không chuyển tiền thật."
          }
        },
        "example": {
          "amount": 250000,
          "order_code": "DH10234",
          "description": "Thanh toan DH10234",
          "return_url": "https://shop.vn/payment/return",
          "cancel_url": "https://shop.vn/checkout",
          "expires_in": 900
        }
      },
      "Checkout": {
        "type": "object",
        "title": "Checkout",
        "required": [
          "id",
          "token",
          "checkout_url",
          "status",
          "amount",
          "currency",
          "order_code",
          "description",
          "qr_code_id",
          "qr_data_url",
          "qr_image_url",
          "bank",
          "return_url",
          "expires_at",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "token": {
            "type": "string",
            "minLength": 32,
            "description": "Token URL-safe dùng cho trang public."
          },
          "checkout_url": {
            "type": "string",
            "format": "uri",
            "example": "https://pay.monapay.vn/c/VlGJtN2dJH_lZ5pU7eKqX8cR3wA9mB4n"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "paid",
              "expired",
              "cancelled"
            ]
          },
          "amount": {
            "type": "integer",
            "minimum": 1000
          },
          "currency": {
            "type": "string",
            "const": "VND"
          },
          "order_code": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "payer_email": {
            "anyOf": [
              {
                "type": "string",
                "format": "email"
              },
              {
                "type": "null"
              }
            ]
          },
          "payer_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "metadata": {
            "anyOf": [
              {
                "type": "object",
                "additionalProperties": true
              },
              {
                "type": "null"
              }
            ]
          },
          "qr_code_id": {
            "type": "string",
            "format": "uuid"
          },
          "qr_data_url": {
            "type": "string"
          },
          "qr_image_url": {
            "type": "string",
            "format": "uri"
          },
          "bank": {
            "type": "object",
            "required": [
              "code",
              "name",
              "account_number",
              "account_name",
              "transfer_content"
            ],
            "properties": {
              "code": {
                "type": "string",
                "example": "ACB"
              },
              "name": {
                "type": "string",
                "example": "Ngân hàng ACB"
              },
              "account_number": {
                "type": "string"
              },
              "account_name": {
                "type": "string"
              },
              "transfer_content": {
                "type": "string"
              }
            }
          },
          "return_url": {
            "type": "string",
            "format": "uri"
          },
          "cancel_url": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "paid_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "transaction_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ]
          },
          "paid_amount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "partial_amount": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "paid_late": {
            "type": "boolean",
            "default": false
          },
          "sandbox": {
            "type": "boolean",
            "default": false
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "access_token từ POST /api/v1/client/login"
      },
      "clientSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Client-Secret",
        "description": "client_secret sinh từ POST /api/v1/client-keys/generate — bắt buộc cho POST/PUT/DELETE"
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ]
}