From f86a7c816222e2479b2781ece249196d7906b14b Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sun, 10 May 2026 20:06:42 +0330 Subject: [PATCH 01/56] Complete APIs documentation --- Insomnia_2026-05-10.json | 97 + Insomnia_2026-05-10.yaml | 11217 ++++++++++++++++ .../src/main/resources/application.yml | 9 + api.csv | 31 + .../src/main/resources/application.yml | 9 + .../ports/binance/config/SecurityConfig.kt | 3 +- api/api-ports/api-opex-rest/pom.xml | 18 +- .../opex/controller/AddressBookController.kt | 68 + .../opex/controller/BankAccountController.kt | 40 + .../opex/controller/DepositController.kt | 19 + .../controller/LocalizationAdminController.kt | 72 + .../ports/opex/controller/OrderController.kt | 4 +- .../opex/controller/StorageAdminController.kt | 54 + .../opex/controller/UserDataController.kt | 39 + .../opex/controller/VoucherController.kt | 23 +- .../opex/controller/WalletAdminController.kt | 44 + .../opex/controller/WithdrawController.kt | 69 + .../src/main/resources/application.yml | 9 + 18 files changed, 11818 insertions(+), 7 deletions(-) create mode 100644 Insomnia_2026-05-10.json create mode 100644 Insomnia_2026-05-10.yaml create mode 100644 api.csv diff --git a/Insomnia_2026-05-10.json b/Insomnia_2026-05-10.json new file mode 100644 index 000000000..98e818626 --- /dev/null +++ b/Insomnia_2026-05-10.json @@ -0,0 +1,97 @@ +{ + "_type": "export", + "__export_format": 4, + "__export_date": "2026-05-10T18:55:00Z", + "__export_source": "junie-discovery", + "resources": [ + { + "_id": "wrk_opex", + "_type": "workspace", + "parentId": null, + "name": "Opex API (Discovery)", + "description": "Discovery-only collection. Enum options and body specs are documented in each request description." + }, + { + "_id": "env_opex_root", + "_type": "environment", + "parentId": "wrk_opex", + "name": "Base Environment", + "data": { + "host": "http://localhost:8094", + "api-host": "http://localhost:8094", + "auth-host": "http://localhost:8083", + "wallet-host": "http://localhost:8091", + "admin-host": "http://localhost:8098", + "config-host": "http://localhost:9088", + "user-token": "", + "admin-token": "", + "client-token": "", + "id": "1", + "withdrawUuid": "00000000-0000-0000-0000-000000000000", + "otpType": "SMS", + "otpCode": "123456", + "currency": "USDT", + "terminalUuid": "terminal-uuid-sample", + "gatewayUuid": "ofg-uuid-sample", + "code": "VCHR-TEST", + "symbol": "BTCUSDT", + "interval": "Month", + "bucket": "public", + "key": "logo.png" + } + }, + + { "_id": "fld_api_opex_rest", "_type": "request_group", "parentId": "wrk_opex", "name": "api-ports / api-opex-rest" }, + + { "_id": "fld_addressbook", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Address Book" }, + { "_id": "req_addr_add", "_type": "request", "parentId": "fld_addressbook", "name": "POST /opex/v1/address-book", "method": "POST", "description": "Body = AddAddressBookItemRequest { name:String, address:String, addressType:String }.\nNotes: addressType: CRYPTO | BANK (NEEDS REVIEW if more types exist).", "url": "{{ _['api-host'] }}/opex/v1/address-book", "body": { "mimeType": "application/json", "text": "{\n \"name\": \"Home Wallet\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_addr_list", "_type": "request", "parentId": "fld_addressbook", "name": "GET /opex/v1/address-book", "method": "GET", "description": "Returns List for authenticated user.", "url": "{{ _['api-host'] }}/opex/v1/address-book", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_addr_delete", "_type": "request", "parentId": "fld_addressbook", "name": "DELETE /opex/v1/address-book/{id}", "method": "DELETE", "description": "Path param: id (int64). Deletes address book entry.", "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_addr_update", "_type": "request", "parentId": "fld_addressbook", "name": "PUT /opex/v1/address-book/{id}", "method": "PUT", "description": "Path param: id (int64). Body = AddAddressBookItemRequest.", "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", "body": { "mimeType": "application/json", "text": "{\n \"name\": \"Updated Name\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + + { "_id": "fld_storage_admin", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Storage Admin" }, + { "_id": "req_storage_get", "_type": "request", "parentId": "fld_storage_admin", "name": "GET /opex/v1/admin/storage", "method": "GET", "description": "Query params: bucket:string, key:string. Returns file bytes.", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { "name": "bucket", "value": "{{ _['bucket'] }}", "description": "Bucket name" }, { "name": "key", "value": "{{ _['key'] }}", "description": "Object key" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_storage_post", "_type": "request", "parentId": "fld_storage_admin", "name": "POST /opex/v1/admin/storage", "method": "POST", "description": "Multipart upload. Params: bucket, key, isPublic (bool). Part: file.", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { "name": "bucket", "value": "{{ _['bucket'] }}", "description": "Bucket name" }, { "name": "key", "value": "{{ _['key'] }}", "description": "Object key" }, { "name": "isPublic", "value": "false", "description": "Publicly accessible if true" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" }, "body": { "mimeType": "multipart/form-data", "params": [ { "name": "file", "type": "file", "fileName": "/path/to/file.png" } ], "paramsOrder": [ "file" ] } }, + { "_id": "req_storage_delete", "_type": "request", "parentId": "fld_storage_admin", "name": "DELETE /opex/v1/admin/storage", "method": "DELETE", "description": "Query params: bucket, key. Deletes file.", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { "name": "bucket", "value": "{{ _['bucket'] }}", "description": "Bucket name" }, { "name": "key", "value": "{{ _['key'] }}", "description": "Object key" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + + { "_id": "fld_withdraw", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Withdraw" }, + { "_id": "req_withdraw_post", "_type": "request", "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw", "method": "POST", "description": "Body = RequestWithdrawBody { currency:String, amount:BigDecimal, destSymbol:String?, destAddress:String, destNetwork:String?, destNote:String?, gatewayUuid:String? }.", "url": "{{ _['api-host'] }}/opex/v1/withdraw", "body": { "mimeType": "application/json", "text": "{\n \"currency\": \"USDT\",\n \"amount\": 50.00,\n \"destSymbol\": null,\n \"destAddress\": \"0x...\",\n \"destNetwork\": null,\n \"destNote\": null,\n \"gatewayUuid\": null\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_withdraw_cancel", "_type": "request", "parentId": "fld_withdraw", "name": "PUT /opex/v1/withdraw/{withdrawUuid}/cancel", "method": "PUT", "description": "Path param: withdrawUuid (string). Cancels withdraw.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/cancel", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_withdraw_find", "_type": "request", "parentId": "fld_withdraw", "name": "GET /opex/v1/withdraw/{withdrawUuid}", "method": "GET", "description": "Path param: withdrawUuid (string). Returns WithdrawResponse.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_withdraw_otp_req", "_type": "request", "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request", "method": "POST", "description": "Path params: withdrawUuid (string), otpType: OTPType = SMS | EMAIL. Triggers OTP send.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/request", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_withdraw_otp_verify", "_type": "request", "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify", "method": "POST", "description": "Path params: withdrawUuid, otpType: OTPType = SMS | EMAIL. Query param: otpCode (string). Verifies OTP.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/verify", "parameters": [ { "name": "otpCode", "value": "{{ _['otpCode'] }}", "description": "OTP code" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + + { "_id": "fld_deposit", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Deposit" }, + { "_id": "req_deposit_post", "_type": "request", "parentId": "fld_deposit", "name": "POST /opex/v1/deposit", "method": "POST", "description": "Body = RequestDepositBody { symbol:String, receiverUuid:String, receiverWalletType:WalletType, amount:BigDecimal, description:String?, transferRef:String?, gatewayUuid:String?, chain:String? }. WalletType values depend on implementation (e.g., MAIN).", "url": "{{ _['api-host'] }}/opex/v1/deposit", "body": { "mimeType": "application/json", "text": "{\n \"symbol\": \"USDT\",\n \"receiverUuid\": \"{{ _['id'] }}\",\n \"receiverWalletType\": \"MAIN\",\n \"amount\": 100.00,\n \"description\": null,\n \"transferRef\": null,\n \"gatewayUuid\": null,\n \"chain\": null\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ] }, + + { "_id": "fld_wallet_admin", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Wallet Admin" }, + { "_id": "req_wallet_admin_users", "_type": "request", "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/users", "method": "GET", "description": "Query: uuid?, currency?, excludeSystem=false, limit?, offset?. Returns List.", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users", "parameters": [ { "name": "excludeSystem", "value": "false", "description": "Exclude system wallets" }, { "name": "limit", "value": "10", "description": "Page size" }, { "name": "offset", "value": "0", "description": "Page offset" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_wallet_admin_system_total", "_type": "request", "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/system/total", "method": "GET", "description": "Returns List.", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/system/total", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_wallet_admin_users_total", "_type": "request", "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/users/total", "method": "GET", "description": "Returns List.", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users/total", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + + { "_id": "fld_voucher", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Voucher" }, + { "_id": "req_voucher_put", "_type": "request", "parentId": "fld_voucher", "name": "PUT /opex/v1/voucher/{code}", "method": "PUT", "description": "Path param: code (string). Returns SubmitVoucherResponse.", "url": "{{ _['api-host'] }}/opex/v1/voucher/{{ _['code'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + + { "_id": "fld_user_data", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "User Data" }, + { "_id": "req_user_data_trade_volume", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/trade/volume", "method": "GET", "description": "Query: symbol (string), interval (Interval = Day | Week | Month | Year). Returns BigDecimal.", "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume", "parameters": [ { "name": "symbol", "value": "{{ _['symbol'] }}", "description": "Symbol, e.g., BTCUSDT" }, { "name": "interval", "value": "{{ _['interval'] }}", "description": "Interval: Day | Week | Month | Year" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_user_data_trade_volume_total", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/trade/volume/total", "method": "GET", "description": "Query: interval (Interval = Day | Week | Month | Year). Returns BigDecimal.", "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume/total", "parameters": [ { "name": "interval", "value": "{{ _['interval'] }}", "description": "Interval: Day | Week | Month | Year" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_user_data_fee", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/fee", "method": "GET", "description": "Returns UserFee.", "url": "{{ _['api-host'] }}/opex/v1/user/data/fee", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_user_data_withdraw_total", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/withdraw/volume/total", "method": "GET", "description": "Query: interval? (label mapped to Interval). Returns BigDecimal.", "url": "{{ _['api-host'] }}/opex/v1/user/data/withdraw/volume/total", "parameters": [ { "name": "interval", "value": "{{ _['interval'] }}", "description": "Optional label: Day | Week | Month | Year" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + + { "_id": "fld_bank_account", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Bank Account" }, + { "_id": "req_bank_add", "_type": "request", "parentId": "fld_bank_account", "name": "POST /opex/v1/bank-account", "method": "POST", "description": "Body = AddBankAccountRequest { name?:String, cardNumber?:String, iban?:String }.", "url": "{{ _['api-host'] }}/opex/v1/bank-account", "body": { "mimeType": "application/json", "text": "{\n \"name\": \"My Bank\",\n \"cardNumber\": null,\n \"iban\": \"IRxxxxxxxxxxxx\"\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_bank_list", "_type": "request", "parentId": "fld_bank_account", "name": "GET /opex/v1/bank-account", "method": "GET", "description": "Returns List.", "url": "{{ _['api-host'] }}/opex/v1/bank-account", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + { "_id": "req_bank_delete", "_type": "request", "parentId": "fld_bank_account", "name": "DELETE /opex/v1/bank-account/{id}", "method": "DELETE", "description": "Path param: id (int64). Deletes bank account.", "url": "{{ _['api-host'] }}/opex/v1/bank-account/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, + + { "_id": "fld_localization_admin", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Localization Admin" }, + { "_id": "req_loc_currency_get", "_type": "request", "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/currency/{currency}/localization", "method": "GET", "description": "Path: currency (string). Returns CurrencyLocalizationResponse.", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_currency_post", "_type": "request", "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/currency/{currency}/localization", "method": "POST", "description": "Path: currency. Body = List { id?:Long, name?:String, title?:String, alias?:String, description?:String, shortDescription?:String, language:String }.", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", "body": { "mimeType": "application/json", "text": "[\n {\n \"id\": null,\n \"name\": \"USDT\",\n \"title\": \"Tether USD\",\n \"alias\": \"Tether\",\n \"description\": \"Stablecoin description\",\n \"shortDescription\": \"Stablecoin\",\n \"language\": \"en\"\n }\n]" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_currency_delete", "_type": "request", "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/currency/localization/{id}", "method": "DELETE", "description": "Path: id (int64). Deletes one currency localization.", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/localization/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_terminal_get", "_type": "request", "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/terminal/{terminalUuid}/localization", "method": "GET", "description": "Path: terminalUuid. Returns TerminalLocalizationResponse.", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_terminal_post", "_type": "request", "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/terminal/{terminalUuid}/localization", "method": "POST", "description": "Path: terminalUuid. Body = List { id?:Long, description?:String, owner?:String, language:String }.", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", "body": { "mimeType": "application/json", "text": "[\n {\n \"id\": null,\n \"description\": \"Terminal description\",\n \"owner\": \"OPEX\",\n \"language\": \"en\"\n }\n]" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_terminal_delete", "_type": "request", "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/terminal/localization/{id}", "method": "DELETE", "description": "Path: id (int64). Deletes one terminal localization.", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/localization/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_gateway_get", "_type": "request", "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/gateway/{gatewayUuid}/localization", "method": "GET", "description": "Path: gatewayUuid. Returns GatewayLocalizationResponse. Route based on prefix of UUID (ofg | ong).", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_gateway_post", "_type": "request", "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/gateway/{gatewayUuid}/localization", "method": "POST", "description": "Path: gatewayUuid. Body = List { id?:Long, depositDescription?:String, withdrawDescription?:String, language:String }.", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", "body": { "mimeType": "application/json", "text": "[\n {\n \"id\": null,\n \"depositDescription\": \"Deposit via this gateway\",\n \"withdrawDescription\": \"Withdraw via this gateway\",\n \"language\": \"en\"\n }\n]" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, + { "_id": "req_loc_gateway_delete", "_type": "request", "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/gateway/{gatewayUuid}/localization/{id}", "method": "DELETE", "description": "Path: gatewayUuid, id (int64). Deletes one gateway localization.", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } } + ] +} diff --git a/Insomnia_2026-05-10.yaml b/Insomnia_2026-05-10.yaml new file mode 100644 index 000000000..58d49b9c8 --- /dev/null +++ b/Insomnia_2026-05-10.yaml @@ -0,0 +1,11217 @@ +type: collection.insomnia.rest/5.0 +schema_version: "5.1" +name: opex +meta: + id: wrk_7773a4a08dff402f8029ba5d5ac718a8 + created: 1776614688089 + modified: 1776614688089 + description: "" +collection: + - name: Opex + meta: + id: fld_c35b513ad37d4fba9464eec8cb135511 + created: 1776615524558 + modified: 1776615524558 + sortKey: -1776615518731 + description: "" + children: + - name: Auth + meta: + id: fld_b017250d23614bfb94f4ba7308bff501 + created: 1776615524560 + modified: 1778084645873 + sortKey: -1776615518730 + description: "" + children: + - url: "{{_['host']}}/storage/-/09a56d8b-f364-4c88-8f8d-3b0a52e72080" + name: Send User File + meta: + id: req_5bd31092fbe44bafad8a1a944f2de465 + created: 1776615524610 + modified: 1776615524610 + isPrivate: false + description: "" + sortKey: -1776615518690 + method: POST + body: + mimeType: multipart/form-data + params: + - name: file + disabled: false + fileName: /C:/Users/Ben/Downloads/overview.jpg + type: file + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['host']}}/storage/-/09a56d8b-f364-4c88-8f8d-3b0a52e72080/overview.jpg" + name: Get User File + meta: + id: req_9f1152e3406849428d02a86c49335426 + created: 1776615524611 + modified: 1776615524611 + isPrivate: false + description: "" + sortKey: -1776615518689 + method: GET + body: + mimeType: multipart/form-data + params: + - name: file + disabled: false + fileName: /C:/Users/Ben/Downloads/overview.jpg + type: file + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{host}}/captcha/generate" + name: Request captcha + meta: + id: req_2229af380bd3414daad8b6d54847c36a + created: 1776615524613 + modified: 1776615524613 + isPrivate: false + description: "" + sortKey: -1776615518688 + method: POST + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: User Registration + meta: + id: fld_ead6fdd431d84b2da146ea0cd3291bba + created: 1776615524562 + modified: 1776615524562 + sortKey: -1776615518729 + description: "" + children: + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user" + name: Create User + meta: + id: req_1133bb24d3504139bf9d7d0b91774b79 + created: 1776615524564 + modified: 1776615534993 + isPrivate: false + description: "" + sortKey: -1776615518728 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"firstName\":\"t4\",\r + + \ \"lastName\":\"tt4\",\r + + \ \"email\":\"test4@gmail.com\",\r + + \ \"password\":\"11111111\",\r + + \ \"passwordConfirmation\":\"11111111\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['client-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user" + name: Create User with Captcha + meta: + id: req_53681726c84f4f1fa64ac79ad4de268a + created: 1776615524567 + modified: 1776615524567 + isPrivate: false + description: "" + sortKey: -1776615518727 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"firstName\":\"test-dtesjیddt1\",\r + + \ \"lastName\":\"test-dtedstیd1j\",\r + + \ \"email\":\"tedst1jt@gdmaiیl.com\",\r + + \ \"username\":\"tesddt_jtیesdt_tets1\",\r + + \ \"captchaAnswer\" : + \"44b95b4fa17a57ca1db2c80be5bc0994f4b6489f110740ce8b9f302b6\ + f4865c8-0b63c250\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['client-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/request-verify" + name: Request Verify Email + meta: + id: req_f8a1d740ad9942cab1913fe6408550fa + created: 1776615524569 + modified: 1776615524569 + isPrivate: false + description: "" + sortKey: -1776615518726 + method: POST + parameters: + - name: email + value: test@opex.dev + disabled: false + - name: captcha + value: 06aecbb42146f3fdc441c804677e283718c14b7fad4656a6de6faa67da729044-7a368 + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/request-forgot" + name: Request Forgot Password + meta: + id: req_da8b75f0ef6b4282846bf7c332678fb8 + created: 1776615524570 + modified: 1776615524570 + isPrivate: false + description: "" + sortKey: -1776615518725 + method: POST + parameters: + - name: email + value: test@opex.dev + disabled: false + - name: captcha + value: "145236" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/forgot" + name: Forgot Password + meta: + id: req_170f302d5fb14adb87f54ca27de0e9e9 + created: 1776615524572 + modified: 1776615524572 + isPrivate: false + description: "" + sortKey: -1776615518724 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"password\": \"12312312\",\r + + \ \"passwordConfirmation\": \"12312312\"\r + + }" + parameters: + - name: key + value: eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhNmRhYWUyOC1hNzZiLTQzNGEtOTY3My04MzQyOWJiNGNiNDUifQ.eyJleHAiOjE2NjEyMDE1MzEsImlhdCI6MTY2MTE1ODMzMSwianRpIjoiOWRlOTNjNjEtOTU0Zi00YWI5LWJiZjMtODE3NjAxMzAwNDBkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwODMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjFlMzRlYjNlLTE1NzctNDQyNC1hMDdkLWIxYmM0MjcwY2JjOSIsInR5cCI6ImV4ZWN1dGUtYWN0aW9ucyIsImF6cCI6ImFjY291bnQiLCJub25jZSI6IjlkZTkzYzYxLTk1NGYtNGFiOS1iYmYzLTgxNzYwMTMwMDQwZCIsInJlZHVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC91c2VyL3ZlcmlmeSIsInJxYWMiOlsiVVBEQVRFX1BBU1NXT1JEIl0sInJxYWMiOlsiVVBEQVRFX1BBU1NXT1JEIl0sInJlZHVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC91c2VyL3ZlcmlmeSJ9.-upcDJO6eclBX_XCgakZEbCBlkKOMBqlbNR3tcssGLg + disabled: false + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Login + meta: + id: fld_ce00ddfb60ae483dbf5c5c0ff778d15c + created: 1776615524573 + modified: 1776615524573 + sortKey: -1776615518723 + description: "" + children: + - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" + name: Get Access Token for Web App Client + meta: + id: req_8e9a118000434c2dbc0c99b8e10d7540 + created: 1776615524574 + modified: 1778083333128 + isPrivate: false + description: "" + sortKey: -1776615518722 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_id + value: web-app + disabled: false + - name: client_secret + value: "{{_['web-app-secret']}}" + disabled: false + - name: grant_type + value: client_credentials + disabled: false + headers: + - name: Content-TypeCo + value: application/jsonapplication/x-www-form-urlencoded + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" + name: Get Access Token for user Web App + meta: + id: req_df379c78d1044eff9029b976ec42da74 + created: 1776615524575 + modified: 1776615524575 + isPrivate: false + description: "" + sortKey: -1776615518721 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_id + value: web-app + disabled: false + - name: username + value: "{{_['test-user-email']}}" + disabled: false + - name: password + value: "{{_['test-user-password']}}" + disabled: false + - name: grant_type + value: password + disabled: false + - name: client_secret + value: "{{_['web-app-secret']}}" + disabled: false + - name: agent + value: postman + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" + name: Get Access Token for admin Web App + meta: + id: req_87f74cee5d21468e9d68bee231ebc2b2 + created: 1776615524576 + modified: 1776615524576 + isPrivate: false + description: "" + sortKey: -1776615518720 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_id + value: web-app + disabled: false + - name: username + value: "{{_['admin-username']}}" + disabled: false + - name: password + value: "{{_['admin-password']}}" + disabled: false + - name: grant_type + value: password + disabled: false + - name: client_secret + value: "{{_['web-app-secret']}}" + disabled: false + - name: agent + value: postman + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + scripts: + afterResponse: "let admin_token=insomnia.response.json().access_token;\r + + insomnia.environment.set(\"admin-token\", admin_token);" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" + name: Get Access Token for super admin Web App + meta: + id: req_3a8a8e6388e0416786f65ed7ece27a71 + created: 1776615524577 + modified: 1776615524577 + isPrivate: false + description: "" + sortKey: -1776615518719 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_id + value: web-app + disabled: false + - name: username + value: "{{_['super-admin-username']}}" + disabled: false + - name: password + value: "{{_['super-admin-password']}}" + disabled: false + - name: grant_type + value: password + disabled: false + - name: client_secret + value: "{{_['web-app-secret']}}" + disabled: false + - name: agent + value: postman + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + scripts: + afterResponse: "let super_admin_token=insomnia.response.json().access_token;\r + + insomnia.environment.set(\"super-admin-token\",super_admin_\ + token);" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "" + name: Get Access Token for user Web App (OTP Enabled) + meta: + id: req_d2633e85649f47f1948a611b3c8ed87a + created: 1776615524579 + modified: 1776615524579 + isPrivate: false + description: "" + sortKey: -1776615518718 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" + name: Refresh Access Token + meta: + id: req_12b181d3503c4f74bc52d6b16ec01352 + created: 1776615524582 + modified: 1776615524582 + isPrivate: false + description: "" + sortKey: -1776615518717 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_secret + value: "{{_['web-app-secret']}}" + disabled: false + - name: client_id + value: web-app + disabled: false + - name: grant_type + value: refresh_token + disabled: false + - name: refresh_token + value: eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMGZmOTk4Mi0xNzhlLTQ5MTAtYjFhNi0yYzdiNTVlYTIzMTYifQ.eyJleHAiOjE2NDY2NTYyODAsImlhdCI6MTY0NjY1NDQ4MCwianRpIjoiNWU1OGYxN2EtZTZhOS00ZDU4LWI0YjgtODgwOGRmZDMwNzg4IiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2L2F1dGgvcmVhbG1zL29wZXgiLCJhdWQiOiJodHRwczovL2RlbW8ub3BleC5kZXYvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6Ijc3YmI4OWMyLWJkYjYtNDc0MS1hYzc1LTY1NTA2YWVjNWU3NCIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJ3ZWItYXBwIiwic2Vzc2lvbl9zdGF0ZSI6IjI2ZGQ4MWY4LTBjNGUtNDFhMy04YThmLTBiNDVlMjVkOTc0MyIsInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCJ9.6h_t7mFHYbBSbasmJgSJSWTR10WsqYMOnuXMhuOep_4 + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://demo.opex.dev/auth/realms/opex/user-management/user/forgot + name: Forgot Password + meta: + id: req_49b96ce4b6fe489e834fa793333259fa + created: 1776615524583 + modified: 1776615524583 + isPrivate: false + description: "" + sortKey: -1776615518716 + method: POST + parameters: + - name: email + value: "{{_['test-user-email']}}" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/logout" + name: Logout + meta: + id: req_e1ca37e6000d4a1fb8a483cce8a91858 + created: 1776615524585 + modified: 1776615524585 + isPrivate: false + description: "" + sortKey: -1776615518715 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/sessions/42c9500\ + 8-5bf6-4eb3-b33c-7635fd1dc8a5/logout" + name: "Logout Using Session Id " + meta: + id: req_a3bad3159e224371a248828d036d208e + created: 1776615524586 + modified: 1776615524586 + isPrivate: false + description: "" + sortKey: -1776615518714 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/sessions/logout" + name: Logout All Sessions Except Current + meta: + id: req_1712ca2f2dc04a01bfc37b70e6d83089 + created: 1776615524587 + modified: 1776615524587 + isPrivate: false + description: "" + sortKey: -1776615518713 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Security + meta: + id: fld_9fc89e0a39ff4793acf8a4691f8cc458 + created: 1776615524589 + modified: 1776615524589 + sortKey: -1776615518712 + description: "" + children: + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/check" + name: Check User Security Configs + meta: + id: req_2a4404ac0aa04d80b1eaf428bed04b80 + created: 1776615524590 + modified: 1776615524590 + isPrivate: false + description: "" + sortKey: -1776615518711 + method: GET + parameters: + - name: username + value: demo5 + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['client-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" + name: "Request Activate OTP " + meta: + id: req_05bad77c39f34e0084f7826fdde35277 + created: 1776615524591 + modified: 1776615524591 + isPrivate: false + description: "" + sortKey: -1776615518710 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/captcha/session" + name: captcha + meta: + id: req_0bd8474f77cf47ad941780142ccde3d4 + created: 1776615524592 + modified: 1776615524592 + isPrivate: false + description: "" + sortKey: -1776615518709 + method: POST + headers: + - name: Content-Type + value: image/jpeg + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" + name: verify captcha + meta: + id: req_f78e4d836bad4af39beda77157a6cf83 + created: 1776615524593 + modified: 1776615524593 + isPrivate: false + description: "" + sortKey: -1776615518708 + method: GET + headers: + - name: Content-Type + value: image/jpeg + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" + name: Activate OTP + meta: + id: req_ff44a6eb7fb24e2f969f5ddf71ea232f + created: 1776615524594 + modified: 1776615524594 + isPrivate: false + description: "" + sortKey: -1776615518707 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"secret\":\"3yFcfhruTNomR9lBMOCks4HSVui2djvw0owN7Qa0O\ + gqqlllWAaluKUeDxIfDRSSK\",\r + + \ \"initialCode\":\"472749\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" + name: Disable OTP + meta: + id: req_6ff31fea8c9144ffb27b54c7c519aaa5 + created: 1776615524595 + modified: 1776615524595 + isPrivate: false + description: "" + sortKey: -1776615518706 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/passwor\ + d" + name: Change Password + meta: + id: req_2adc6df3a5fb477381b62ceb61d07abc + created: 1776615524597 + modified: 1776615524597 + isPrivate: false + description: "" + sortKey: -1776615518705 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"password\":\"demo1\",\r + + \ \"newPassword\":\"12345\",\r + + \ \"confirmation\":\"12345\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/sessions" + name: Get Sessions + meta: + id: req_f463b77cb9a74cf4833c5ab4fadac21c + created: 1776615524598 + modified: 1776615524598 + isPrivate: false + description: "" + sortKey: -1776615518704 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: _depricated + meta: + id: fld_c20237e206f843cbb3ec48ea733fc3a1 + created: 1776615524599 + modified: 1776615524599 + sortKey: -1776615518703 + description: "" + children: + - url: https://api.opex.dev/auth/realms/opex/protocol/openid-connect/token + name: Get Access Token for Client ( expired ) + meta: + id: req_df18014ed48f4e128fea048bb97d77e3 + created: 1776615524600 + modified: 1776615524600 + isPrivate: false + description: "" + sortKey: -1776615518702 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_id + value: account-console + disabled: false + - name: client_secret + value: fae6f87e-5b66-435c-b5aa-fd42c7641604 + disabled: false + - name: grant_type + value: client_credentials + disabled: false + headers: + - name: Content-TypeCo + value: application/jsonapplication/x-www-form-urlencoded + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev/auth/realms/opex/protocol/openid-connect/token + name: Get Access Token for user (expired) + meta: + id: req_0b5f179099c2439c95d62728f4ada79c + created: 1776615524601 + modified: 1776615524601 + isPrivate: false + description: "" + sortKey: -1776615518701 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_id + value: admin-cli + disabled: false + - name: username + value: opex1 + disabled: false + - name: password + value: "123456" + disabled: false + - name: grant_type + value: password + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev/auth/admin/realms/opex/users + name: Create User + meta: + id: req_ff8cabe65c0048358625834a5e511d42 + created: 1776615524602 + modified: 1776615524602 + isPrivate: false + description: "" + sortKey: -1776615518700 + method: POST + body: + mimeType: text/plain + text: "{\r + + \ \t\"createdTimestamp\": 1588880747548,\r + + \ \t\"username\": \"hossein2\",\r + + \ \t\"enabled\": true,\r + + \ \t\"totp\": false,\r + + \ \t\"emailVerified\": true,\r + + \ \t\"firstName\": \"Hossein\",\r + + \ \t\"lastName\": \"Abolhasani\",\r + + \ \t\"email\": \"hossein2@nilin.co\",\r + + \ \t\"disableableCredentialTypes\": [],\r + + \ \t\"requiredActions\": [],\r + + \ \t\"notBefore\": 0,\r + + \ \t\"access\": {\r + + \ \t\"manageGroupMembership\": true,\r + + \ \t\"view\": true,\r + + \ \t\"mapRoles\": true,\r + + \ \t\"impersonate\": true,\r + + \ \t\"manage\": true\r + + \ \t},\r + + \ \t\"realmRoles\": [ \"mb-user\" ]\r + + \t}\r\n" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjQxNzg4NDgsImlhdCI6MTYyNDE3ODU0OCwianRpIjoiZDhjYTJkZDItYWQ3ZS00MDdlLWJmNGMtMGQwMTYyZWI2YTMxIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InJlYWxtLW1hbmFnZW1lbnQiOnsicm9sZXMiOlsibWFuYWdlLXVzZXJzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiXX19LCJzY29wZSI6InRydXN0IHByb2ZpbGUgZW1haWwiLCJjbGllbnRJZCI6ImFjY291bnQtY29uc29sZSIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xNiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LWFjY291bnQtY29uc29sZSIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xNiJ9.F3MkEklXf3lWDXijIHL0IQ2-tRZCWrLnF0yl5eh2jC1ur7qq70oz_q71N7qAiM7vjtzz4ByYS93JVqd98Ixsuvaa85SthWwOTxcpJNEz3LnD5catNMKAvBZUN1P0WTPzwmfAZQqoEnbiJ7pDSCa0rOltDf5k-B1ksnknjZOw2RHEuIusuOOs9qdtllbJpTFukWWa6LCR1yLSCQOeWByO_xz5cZ9GGgllIgqIPCrOFZY6M913K4w5GaSJQPCLGUyMUFIPyEUdEj4Eis0zjV-8JEH6b-Z7PjjfHUPFGjQ5vSqxPTzjQAKkqxaGdl1UwBNMHNPLcvSeNO4DuHlNgcPqOg + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev/auth/admin/realms/mixchange/users/478cf5d5-5922-413a-b9cb-74e3a860afec/send-verify-email + name: Send Verify Email email + meta: + id: req_b1e4b306455d4344b94515f9272ab0c1 + created: 1776615524603 + modified: 1776615524603 + isPrivate: false + description: |- + User_id : get from Get User Endpoint + + Token : get from Get Access Token for Client + sortKey: -1776615518699 + method: PUT + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjcyOTI3NDQsImlhdCI6MTYyNzI5MjQ0NCwianRpIjoiMzU1NTAwZjgtNDMxOC00NDJlLThlYmYtYmU2ZWQxNzExNzNjIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9vcGV4LmRldiIsImh0dHBzOi8vYXBpLm9wZXguZGV2Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJtYW5hZ2UtdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoiYWNjb3VudC1jb25zb2xlIiwiY2xpZW50SG9zdCI6IjE3Mi4xOC4wLjE4IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtYWNjb3VudC1jb25zb2xlIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjE4In0.sFayDCOv8HFVlDwhX9iWoTfBcTeT3bo7SzEbA_xoexMCqnH6-tmFV98ShfPNh6l5olVwH-_m23f2ghy21NadKgYNklk1Z-oDLs905c0CfI5bR6z1RJSljTOBvfU3hwXZImvBJSKVO3Ut52kgv_ETE10Y_FtxsOMs1PUbFd_AXbFGhN2nzLzg-7_0FiQwQvNmj1jtFGKeHJfIcpsnVQ5QF8VxUgee1cIFvXH3tZvnFvTL66EhV6_6nMGZGV4ql1J5IoYwp5LNh2BqstZp1YWk_prAQM5tt-adX4GHSA1UFUQnyEfpd6qGOGhyCEaTP8S0_s57YrFhiZO86NRKXMKk3A + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev/auth/admin/realms/mixchange/users/5837ff71-129b-44ef-a1af-9bd6378f9e37/execute-actions-email + name: Send Reset password + meta: + id: req_4a1aa9a071e34fc8b951e6b12b85b5ca + created: 1776615524604 + modified: 1776615524604 + isPrivate: false + description: |- + User_id : get from Get User Endpoint + + Token : get from Get Access Token for Client + sortKey: -1776615518698 + method: PUT + body: + mimeType: text/plain + text: '["UPDATE_PASSWORD"]' + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjczMDYxNzMsImlhdCI6MTYyNzMwNTg3MywianRpIjoiYmVhMmZkNDgtMWIzZS00YTc3LTgzODAtMWYzNDgzNTBkYWYzIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9vcGV4LmRldiIsImh0dHBzOi8vYXBpLm9wZXguZGV2IiwiaHR0cDovL2xvY2FsaG9zdDozMDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJtYW5hZ2UtdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoiYWNjb3VudC1jb25zb2xlIiwiY2xpZW50SG9zdCI6IjE3Mi4xOC4wLjE4IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtYWNjb3VudC1jb25zb2xlIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjE4In0.VFMkDZXbvLyrEbKVnRuxx1oQu7qz8sE8_1h4LvDmegCOJ5_nZwTdybeb5N1QAk96P-H9uFXgU0wCf4M8YDhMl1dKnyculixAMJZJgqROTjsgikVhYcWVn7a3uHKGik1XPt5vDJ4IxzcwnNDrY--cJKQHGAOHdC9kKO6X9F5HmR8ypWjYb8PUQrJSBioNSZcGjLnxZM3EHWq4vnlRp4tBn1v40oUG15HC-OM7yIjlFDnXxzeq3RnXXurQmY7JUX8gUhXRC721pfiTj0iSlGpnPhMx_f0nT-xsckNtk-bWn7S98WFgQYXKnPjnjVe-TRfN5hi2JlTTiccIyujworyYUw + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev/auth/admin/realms/mixchange/users + name: Get User + meta: + id: req_81dbd4aa33a1424997884d320f91cdd6 + created: 1776615524604 + modified: 1776615524604 + isPrivate: false + description: "" + sortKey: -1776615518697 + method: GET + parameters: + - name: username + value: maryam + disabled: false + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjcyOTEwNjksImlhdCI6MTYyNzI5MDc2OSwianRpIjoiYWIxZTVlNjctNjQ1NC00OTE0LWFkOWQtZDkxYzA5NzZkNmZkIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9vcGV4LmRldiIsImh0dHBzOi8vYXBpLm9wZXguZGV2Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJtYW5hZ2UtdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoiYWNjb3VudC1jb25zb2xlIiwiY2xpZW50SG9zdCI6IjE3Mi4xOC4wLjE4IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtYWNjb3VudC1jb25zb2xlIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjE4In0.CIMkiCIRKBQXCKb4-IuCGKLhDfEkMVwSPHreZcusXjgAe1Su8ENmWgNvTNtDqzgVYCEz74R_fHbihACT8F_sCdN7oK1lP-gWaQuqFRpnaNBclufne-uQtQtdJdF9JMppIpNU7PKy0QBXh4Oz2_GHRBuaHJQSJbja3ZIqm9P-wsBFcY6LXXQagqHtloohgphQ3UhAIWdqICmOhC9QvTdbcvCX0kGZrQRMw8FXsMm26Y652j7jMGJTtfaU4IJ2RB0AlbVYLDbDCh5Y0LGJULt46C7eiV17pbGBihcqXVl92eidt4znORmDhdNdag47aEEqPRLeq0rV0AmhIjgoSI9P0A + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: API Key + meta: + id: fld_64e4017b2aa9441cac0fd8ab9cc52339 + created: 1776615524605 + modified: 1776615524605 + sortKey: -1776615518696 + description: "" + children: + - url: "{{_['api-host']}}/v1/api-key" + name: Get API Key List + meta: + id: req_66884d9810f147d390e1eddff947b718 + created: 1776615524606 + modified: 1776615524606 + isPrivate: false + description: "" + sortKey: -1776615518695 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/api-key" + name: Create API Key + meta: + id: req_a0ac499f74bf43cf9f0ba0e0c2c75bb2 + created: 1776615524607 + modified: 1776615524607 + isPrivate: false + description: "" + sortKey: -1776615518694 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"label\":\"my api key 2\", \r + + \ \"expiration\":\"ONE_MONTH\", // optional - [ONE_MONTH, + THREE_MONTHS, SIX_MONTHS, ONE_YEAR]\r + + \ \"allowedIPs\":\"185.54.69.35,156.255.234.210\" // + optional\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/api-key/a1fb2e91-7cd5-49e2-afad-cf75a726590e/enable" + name: Enable API Key + meta: + id: req_89f34fab6f934048bc1ebd23a9d21d9f + created: 1776615524608 + modified: 1776615524608 + isPrivate: false + description: "" + sortKey: -1776615518693 + method: PUT + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/api-key/a1fb2e91-7cd5-49e2-afad-cf75a726590e" + name: Delete API Key + meta: + id: req_2877bfab133e40d09d9ffab7bd5a5b4d + created: 1776615524609 + modified: 1776615524609 + isPrivate: false + description: "" + sortKey: -1776615518691 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/api-key/a1fb2e91-7cd5-49e2-afad-cf75a726590e/disable" + name: Disable API Key + meta: + id: req_3bbd3e79d64f490abb64bde5ed3545d2 + created: 1776615524609 + modified: 1776615524609 + isPrivate: false + description: "" + sortKey: -1776615518692 + method: PUT + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Auth (new) + meta: + id: fld_19acd55699594749b15533d4f070f6e7 + created: 1776615524614 + modified: 1776615524614 + sortKey: -1776615518687 + description: "" + children: + - url: "{{_['v2auth-host']}}/v1/user/public/register" + name: Request register + meta: + id: req_c961989a6791465dace6d0a5ef5a1a87 + created: 1776615524615 + modified: 1778083333128 + isPrivate: false + description: "" + sortKey: -1776615518686 + method: POST + body: + mimeType: application/json + text: |- + { + "username": "09212880961", // use mobile OR email + "firstName": "Amir", + "lastName": "Rajabi", + "captchaCode" : "1" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/public/register/verify" + name: Verify register + meta: + id: req_84eec8dde7c945f192a9f753b132e394 + created: 1776615524616 + modified: 1776615524616 + isPrivate: false + description: "" + sortKey: -1776615518685 + method: POST + body: + mimeType: application/json + text: |- + { + "username": "hi@opex.dev", + "otp": "48278044" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/public/register/confirm" + name: Confirm register + meta: + id: req_50b17e2234714866b99f33af7b43009b + created: 1776615524617 + modified: 1776615524617 + isPrivate: false + description: "" + sortKey: -1776615518684 + method: POST + body: + mimeType: application/json + text: >- + { + "password": "12345678", + "clientId": "web-app", + "clientSecret": "R9r4amsuwruXacttDwRQBwTS3mEB3FGM", + "rememberMe": true, + "token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvcGV4LWF1dGgiLCJ1c2VySWQiOiJhbWlyQG9wZXguZGV2IiwiYWN0aW9uIjoiUkVHSVNURVIiLCJpYXQiOjE3NTI5MjY3ODUsImV4cCI6MTc1MjkyNjkwNX0.Pv7dkRFYKLgG1QIlcN-6n7sdcliGHEl3wR7B3fDnwalQxjhFLAbIP7qJRtJMjBscSSqJra2MnAxjxeTD527f3n8w8Afa6rm1QGrVpVLTTyIj_6_wmmEKkUquxVQfrjsFdQuf4o0d3H3Yhr2btUPe6Ugn_qDmVCiNk-sjMaogsxr7tXdV9_7x7mXZMd7FSYXT7uwtGU9Vn1ywt1GRy_XaPYVJJE6ifTCBK7GO_atkBkXgFmk9V2rSn7h3E4wQySYj8i2YPUC8r_Is84UTVryzKt-XOP6Veih_uys8Q2INW24CmCm_aiGjyNy3uUiDGMSxsLYfQFap60piX6uJS5Lvrg" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" + name: Request login (otp required) + meta: + id: req_87359bd6a4a14f6baa34139436a3979f + created: 1776615524617 + modified: 1776615524617 + isPrivate: false + description: "" + sortKey: -1776615518683 + method: POST + body: + mimeType: application/json + text: >- + { + "username": "09336461763", // use mobile OR email for username + "password": "12345678", + "clientId": "web-app", + "clientSecret": "4GNyfRVqy7YLBjnWUZWprYfvPQT3sZbQ", + "rememberMe": true, + // "captchaType" :"INTERNAL" optional (default = INTERNAL ) {INTERNAL , ARCHAPTCHA , HCAPTCHA} + "captchaCode" :"edcd2" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" + name: Request login (super-admin) (otp required) + meta: + id: req_48778e02f8314d6a9f2855e9e2c19322 + created: 1776615524618 + modified: 1776615524618 + isPrivate: false + description: "" + sortKey: -1776615518682 + method: POST + body: + mimeType: application/json + text: >- + { + "username": "{{_['super-admin-username']}}", // use mobile OR email for username + "password": "{{_['super-admin-password']}}", + "clientId": "web-app", + "clientSecret": "iXGYTDsCgY6lhaOFJE8GwpUpc5HQ95Wl", + "rememberMe": true, + // "captchaType" :"INTERNAL" optional (default = INTERNAL ) {INTERNAL , ARCHAPTCHA , HCAPTCHA} + "captchaCode" :"edcd2" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" + name: Login (otp required) + meta: + id: req_c215589715bd48d2ad6c02e4f3a53957 + created: 1776615524619 + modified: 1776615524619 + isPrivate: false + description: "" + sortKey: -1776615518681 + method: POST + body: + mimeType: application/json + text: >- + { + "username": "09905135295", // use mobile OR email for username + "password": "Opex@1234", + "clientId": "web-app", + "captchaCode": "asdfasdf", + "rememberMe": true + } + headers: + - name: Content-Type + value: application/json + scripts: + afterResponse: "let user_token=insomnia.response.json().access_token;\r + + insomnia.environment.set(\"user-token\",user-token);" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token/confirm" + name: Login (otp required) Confirm + meta: + id: req_50ad784d186945d881fcdf55ce55d7af + created: 1776615524620 + modified: 1776615524620 + isPrivate: false + description: "" + sortKey: -1776615518679 + method: POST + body: + mimeType: application/json + text: >- + { + "username": "09905135295", // use mobile OR email for username + "token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1NktVakxFVUFFTEVDQUZwbUtnMEY3emI0TVhWRGdXSlVkUldRNk5nYXlRIn0.eyJleHAiOjE3NjU4MTM5MDYsImlhdCI6MTc2NTgxMzc4NiwianRpIjoiZTFlOTk4M2ItZDYwYi00YjkyLWIxZDctOTdjOTYyMjQ5ZDQxIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwcmUtYXV0aC1jbGllbnQiLCJzaWQiOiIxMTczOTcwMy1lMDBkLTRkZGItYTJjMS0xMGE5ZTcyMmI1MzQiLCJzY29wZSI6IiJ9.K3162xOskqrR_ODW5NT5ZRTjZlkc9EREZ4mOuPgn0lj4XqLcvoo2fOEAlG5YTswWXro6LDsDpvPsleAwsoDSCZjtscvykc9_auRChOcMNdx-LXwazdKHvfh-8g0qaPJEqphk6H2YDPul58kpK5BYrwp9zeJ7ZnEjESinDGJBlkAEReSgU2RPXJrphy2sMX5qHHPLR71fgX9IZBY14UF4_ty2FNFacL2H6rX9QADpeSow447tva6zRBnBxitC3Kt1oVzTJ4b9I4EVnNDWE1jVr4Ks2tGbqFr09DXgcWfxi5JvxBQpRfPCs1C9FPAop6rnmNOHplGEyH4QBcrQNlhvew", + "clientId": "web-app", + "otp": "598757", + "rememberMe": true + } + headers: + - name: Content-Type + value: application/json + scripts: + afterResponse: "let user_token=insomnia.response.json().access_token;\r + + insomnia.environment.set(\"user-token\",user-token);" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token/resend-otp" + name: resend otp + meta: + id: req_6c59db28182e40ac9cff8476817756b0 + created: 1776615524620 + modified: 1776615524620 + isPrivate: false + description: "" + sortKey: -1776615518680 + method: POST + body: + mimeType: application/json + text: |- + { + "username": "09905135295", + "clientId":"" + + } + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + scripts: + afterResponse: "let user_token=insomnia.response.json().access_token;\r + + insomnia.environment.set(\"user-token\",user-token);" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" + name: Login (no otp) + meta: + id: req_8d6fa0dff9b14e4b8bc516c2cff637cf + created: 1776615524621 + modified: 1778084439929 + isPrivate: false + description: "" + sortKey: -1776615518678 + method: POST + body: + mimeType: application/json + text: |- + { + "username": "admin@opex.dev", + "password": "Opex@1234", + "clientId": "web-app", + "rememberMe": false, + "captchaCode": "aaa" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" + name: Login (super-admin) + meta: + id: req_cc83a683459045c2a8a5fc344f8928f8 + created: 1776615524622 + modified: 1776615524622 + isPrivate: false + description: "" + sortKey: -1776615518677 + method: POST + body: + mimeType: application/json + text: >- + { + "username": "{{_['super-admin-username']}}", // use mobile OR email for username + "password": "{{_['super-admin-password']}}", + "clientId": "web-app", + "clientSecret": "4GNyfRVqy7YLBjnWUZWprYfvPQT3sZbQ", + "captchaCode": "aaa", + "rememberMe": false, + "token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NjY5NDQzMzYsImlhdCI6MTc2Njk0NDIxNiwianRpIjoiOWU5MTc3YmQtNzFkNS00MWNiLTkwYTMtMmE0YmNmOWU0MWI1IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsicHJlLWF1dGgtY2xpZW50IiwiYWNjb3VudCJdLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwcmUtYXV0aC1jbGllbnQiLCJzaWQiOiJhMGVmNTUyYy0yNmE3LTQxNDgtOWRmOC0xNzNkYTY3MDZlZjgiLCJzY29wZSI6IiJ9.dy5FlJiVOXccxCbF2pZcGc_tm5n-DlwkFfCpeSEiQf2xeb54Zs4FmOa8odCbhDnILwnDrfhjYZl-VOH6kycsd2JN6B82OtXaadksURu8Za6Xr3KMXBtxEjjTOEzM_co-TBttSeM_QM0E_X94MWccUc9cmheRy_P9Y__qe7x5Fcgo4jJz0qSD5B-TJD4VZSJJud2UPHMLOfqzPg3n16Wa7cbatuebJOxCRQGBM5r1bqfOq745SZXhDWbCmGcMFY2AIn3JowDvzGivHLN-4wN341r-YTLmFwPvCmMD47-nKVWqsQOU2-k_0kikFpThaxNp-NZzjXYHbwLKOvBJX93pGA", + "otp": 742560 + } + headers: + - name: Content-Type + value: application/json + scripts: + afterResponse: >- + let + super_admin_token=insomnia.response.json().token.access_token; + + insomnia.environment.set("super-admin-token",super_admin_token); + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" + name: Login (super-admin) otp-required confirm + meta: + id: req_0f617db070134287bbbc25ba2825d8c2 + created: 1776615524623 + modified: 1776615524623 + isPrivate: false + description: "" + sortKey: -1776615518676 + method: POST + body: + mimeType: application/json + text: >- + { + "username": "{{_['super-admin-username']}}", // use mobile OR email for username + "password": "{{_['super-admin-password']}}", + "clientId": "web-app", + "clientSecret": "4GNyfRVqy7YLBjnWUZWprYfvPQT3sZbQ", + "captchaCode": "aaa", + "rememberMe": false, + "token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NjY5NDQzMzYsImlhdCI6MTc2Njk0NDIxNiwianRpIjoiOWU5MTc3YmQtNzFkNS00MWNiLTkwYTMtMmE0YmNmOWU0MWI1IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsicHJlLWF1dGgtY2xpZW50IiwiYWNjb3VudCJdLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwcmUtYXV0aC1jbGllbnQiLCJzaWQiOiJhMGVmNTUyYy0yNmE3LTQxNDgtOWRmOC0xNzNkYTY3MDZlZjgiLCJzY29wZSI6IiJ9.dy5FlJiVOXccxCbF2pZcGc_tm5n-DlwkFfCpeSEiQf2xeb54Zs4FmOa8odCbhDnILwnDrfhjYZl-VOH6kycsd2JN6B82OtXaadksURu8Za6Xr3KMXBtxEjjTOEzM_co-TBttSeM_QM0E_X94MWccUc9cmheRy_P9Y__qe7x5Fcgo4jJz0qSD5B-TJD4VZSJJud2UPHMLOfqzPg3n16Wa7cbatuebJOxCRQGBM5r1bqfOq745SZXhDWbCmGcMFY2AIn3JowDvzGivHLN-4wN341r-YTLmFwPvCmMD47-nKVWqsQOU2-k_0kikFpThaxNp-NZzjXYHbwLKOvBJX93pGA", + "otp": 742560 + } + headers: + - name: Content-Type + value: application/json + scripts: + afterResponse: >- + let + super_admin_token=insomnia.response.json().token.access_token; + + insomnia.environment.set("super-admin-token",super_admin_token); + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/refresh" + name: Refresh token + meta: + id: req_4ca3ae7053784e94a1b14307921dad52 + created: 1776615524624 + modified: 1776615524624 + isPrivate: false + description: "" + sortKey: -1776615518675 + method: POST + body: + mimeType: application/json + text: >- + { + "clientId": "web-app", + "clientSecret": "iXGYTDsCgY6lhaOFJE8GwpUpc5HQ95Wl", + "refreshToken": "eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjNzIxNTM2OS1hOTlmLTQ0ZDAtYmIxMC1iNzY2MDkyNTUyODYifQ.eyJleHAiOjE3NDcwNTA4MTYsImlhdCI6MTc0NTg0MTIxNiwianRpIjoiYjJmODYwYzAtZGFjMC00M2JlLWFjNzMtZTVhOGZjMmE5ZGJkIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJodHRwOi8va2V5Y2xvYWs6ODA4MC9yZWFsbXMvb3BleCIsInN1YiI6IjE0MmIyNTMwLTI4YjUtNDA2NC05ZWEyLWY5YzRjNWE3NjQ5MyIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiMTAyZWNiNzktZDk5MS00MWM2LTg0ZDctOWQ1M2JkMDgxMTQ2Iiwic2NvcGUiOiJiYXNpYyByb2xlcyBhY3IgdHJ1c3QgcHJvZmlsZSBlbWFpbCB3ZWItb3JpZ2lucyJ9.uRWwoVHmD9KG2hCtNpL-KbE-kU3OXjCBhXg-ljjbV-wVyAXHB1a0IhaxPV36sNHjTHmccYa7s1oQXaTL7gRQ7Q" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/logout" + name: Logout + meta: + id: req_8c623db26c06403fbca86df8770477fc + created: 1776615524625 + modified: 1776615524625 + isPrivate: false + description: "" + sortKey: -1776615518674 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/public/forget" + name: Request forget + meta: + id: req_bd89c659d6354ac38c55f5b9b9d2dbae + created: 1776615524625 + modified: 1776615524625 + isPrivate: false + description: "" + sortKey: -1776615518673 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"username\" :\"hi@gmail.com\",\r + + \ // \"captchaType\" :\"INTERNAL\" optional (default = + INTERNAL ) {INTERNAL , ARCHAPTCHA , HCAPTCHA}\r + + \ \"captchaCode\" :\"edcd2\"\r + + }" + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/public/forget/verify" + name: Verify forget + meta: + id: req_a8d41f04010a4bbf83cb26d244ecd363 + created: 1776615524626 + modified: 1776615524626 + isPrivate: false + description: "" + sortKey: -1776615518672 + method: POST + body: + mimeType: application/json + text: |- + { + "username": "hi@gmail.com", + "otp": "xPFSWwEU" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/public/forget/confirm" + name: Confirm forget + meta: + id: req_495ecfb6e2974edea4589bb961cd768b + created: 1776615524627 + modified: 1776615524627 + isPrivate: false + description: "" + sortKey: -1776615518671 + method: POST + body: + mimeType: application/json + text: >- + { + "newPassword": "22222222", + "newPasswordConfirmation": "22222222", + "token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvcGV4LWF1dGgiLCJ1c2VySWQiOiJoaUBnbWFpbC5jb20iLCJhY3Rpb24iOiJGT1JHRVQiLCJpYXQiOjE3NDY5NjgzOTksImV4cCI6MTc0Njk2ODUxOX0.D_C00eBpWkqH2KIYgXKjlp1PMRW6uyCkcUHlCtGjfZxOG51k2d_4HSJDzThVgaHY1KZsj15ExCX3U1Vxi4OCtG1_oh_g5MH7J3suxcRS5MMv-VONDwekrgCmL0aUHiqg7pu6GlYRBsL8lSIuVJF6g4M6MQUCXerKFAxzaiDiJ9fjl2a9tENw2il9OY68GsHoGajju0iA8UIHeRLZq5B--LjtI9K6e8Aj0UWHv9Tw6d3ikGncwEefA12iL-ZVnnxso3Mq87fte--J6B-dcFlY6o2NzanT6ve5PHGkjt6RPsw_DEGrSoOXnm4Ot_f0tmfWsB8xKKCt0TZgP3qL6ZTbDA" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/session" + name: Active sessions + meta: + id: req_f13952ee397f48deb0a4c297348b00dc + created: 1776615524627 + modified: 1776615524627 + isPrivate: false + description: "" + sortKey: -1776615518670 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/session/e79dc8df-05be-494a-9441-e84108f564d9" + name: Delete one sessions + meta: + id: req_039141c92ecc4774bdd42fc5cd017d38 + created: 1776615524628 + modified: 1776615524628 + isPrivate: false + description: "" + sortKey: -1776615518669 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/session/delete-others" + name: Delete other sessions + meta: + id: req_cd0b6593c83a47e48993a59fb4560865 + created: 1776615524629 + modified: 1776615524629 + isPrivate: false + description: "" + sortKey: -1776615518668 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/session/delete-all" + name: Delete all sessions + meta: + id: req_8af92ab15e1849bcb440ee5475015b64 + created: 1776615524630 + modified: 1776615524630 + isPrivate: false + description: "" + sortKey: -1776615518667 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['v2auth-host']}}/v1/user/session" + name: Sessions + meta: + id: req_2855e1e36ee04cedb5c7d6841542e1d6 + created: 1776615524631 + modified: 1776615524631 + isPrivate: false + description: "" + sortKey: -1776615518666 + method: POST + body: + mimeType: application/json + text: >- + { + + "limit": 10, + "offset": 0, + "ascendingByTime": false, + "os": "ANDROID", //nul, ANDROID, IOS, MOBILE_WEB, DESKTOP_WEB + "status": "ACTIVE"// ACTIVE, EXPIRED, TERMINATED + } + headers: + - name: Accept-Language + value: EN + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Wallet + meta: + id: fld_1b63e4888c724c699368c73b7a819c3e + created: 1776615524632 + modified: 1776615524632 + sortKey: -1776615518665 + description: "" + children: + - url: "{{_['api-host']}}/v3/account" + name: Account Info + meta: + id: req_55e99e558fb945a48238ccbfd917f8e7 + created: 1776615524645 + modified: 1776615524645 + isPrivate: false + description: "" + sortKey: -1776615518649 + method: GET + parameters: + - name: timestamp + value: "1626805452" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{host}}/sapi/v1/capital/deposit/address" + name: Address + meta: + id: req_cab2137066cc49a8a430c9f1e779ec99 + created: 1776615524645 + modified: 1776615524645 + isPrivate: false + description: "" + sortKey: -1776615518648 + method: GET + parameters: + - name: coin + value: TUSDT + disabled: false + - name: timestamp + value: "1" + disabled: false + - name: network + value: test-tron + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/balanceOf/wallet_type/main/currency/usdt" + name: Balance Of + meta: + id: req_3c5422fbdf724cea8146e85608e2b81b + created: 1776615524647 + modified: 1776615524647 + isPrivate: false + description: "" + sortKey: -1776615518647 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{host}}/sapi/v1/capital/withdraw/history" + name: Withdraw + meta: + id: req_bbd3bbd0aca94e108258b1a9ef69e893 + created: 1776615524647 + modified: 1776615524647 + isPrivate: false + description: "" + sortKey: -1776615518646 + method: GET + parameters: + - name: coin + value: eth + disabled: false + - name: timestamp + value: "1" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/transaction/86e471f8-c818-4b9a-9198-23f269c9cb9e" + name: Transaction History + meta: + id: req_10683ed1a5c4400d8d97ed66012c4b4e + created: 1776615524648 + modified: 1776615524648 + isPrivate: false + description: "" + sortKey: -1776615518645 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"coin\": \"BTC\", // optional\r + + \ \"category\": \"DEPOSIT\", // optional [DEPOSIT, FEE, + TRADE, WITHDRAW, ORDER_CANCEL, ORDER_CREATE, ORDER_FINALIZED]\r + + \ \"startTime\": 1662190330000,\r + + \ \"endTime\": 1693828960000,\r + + \ \"limit\": 10,\r + + \ \"offset\": 0\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/v1/deposit/manually/20_USDT/dcb7c726-8e0e-40ba-a8c7-\ + 5a017905176d" + name: Deposit Manually + meta: + id: req_870e61c294a040308c6852c6bb996325 + created: 1776615524649 + modified: 1776615524649 + isPrivate: false + description: "" + sortKey: -1776615518644 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"description\":\"Sign up gift\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{host}}/sapi/v1/capital/deposit/hisrec" + name: Deposit + meta: + id: req_f27e0ce346c2493f8e3948a6800b9549 + created: 1776615524650 + modified: 1776615524650 + isPrivate: false + description: "" + sortKey: -1776615518643 + method: GET + parameters: + - name: coin + value: eth + disabled: false + - name: timestamp + value: "1" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: stats + meta: + id: fld_e5abe1a673bb4d8ca0e6b8aa322bdd17 + created: 1776615524633 + modified: 1776615524633 + sortKey: -1776615518664 + description: "" + children: + - url: "{{_['wallet-host']}}/stats/wallets" + name: Wallet Data + meta: + id: req_ed14cf56e952499d93b73ded60a3fbed + created: 1776615524633 + modified: 1776615524633 + isPrivate: false + description: "" + sortKey: -1776615518663 + method: GET + parameters: + - name: uuid + value: b15b185b-5b4c-4cca-beea-d449e1503bc1 + disabled: false + - name: walletType + value: MAIN + disabled: false + - name: currency + value: TUSDT + disabled: false + - name: excludeSystem + value: "true" + disabled: false + - name: limit + value: "100" + disabled: false + - name: offset + value: "0" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/stats/wallets/system/total" + name: Wallet Total System + meta: + id: req_5e234211b97f4f87a102556e8ae41266 + created: 1776615524634 + modified: 1776615524634 + isPrivate: false + description: "" + sortKey: -1776615518662 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/stats/wallets/user/total" + name: Wallet Total Users + meta: + id: req_7447cf97c0c8499da0b75df034456bce + created: 1776615524635 + modified: 1776615524635 + isPrivate: false + description: "" + sortKey: -1776615518661 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/stats/v2/wallets" + name: Wallet Data V2 + meta: + id: req_8e67204e187c4d73b896548639f91004 + created: 1776615524636 + modified: 1776615524636 + isPrivate: false + description: "" + sortKey: -1776615518660 + method: GET + parameters: + - name: uuid + value: 29599226-61e3-41fd-9f2d-c801b78f9400 + disabled: false + - name: currency + value: USDT + disabled: false + - name: excludeSystem + value: "true" + disabled: false + - name: limit + value: "10" + disabled: false + - name: offset + value: "0" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Withdraw + meta: + id: fld_036ed18225b44cc6a6ece9b3272b2482 + created: 1776615524637 + modified: 1776615524637 + sortKey: -1776615518659 + description: "" + children: + - url: "{{_['wallet-host']}}/withdraw" + name: Request withdraw + meta: + id: req_4753671c2938421c83184f28a01f4840 + created: 1776615524637 + modified: 1776615524637 + isPrivate: false + description: "" + sortKey: -1776615518658 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"currency\": \"USDT\",\r + + \ \"gatewayUuid\":\"121\"\r + + \ \"amount\": 1,\r + + \ \"destAddress\": + \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r + + \ \"destNetwork\": \"test-ethereum\",\r + + \ \"destNote\": \"Personal wallet\", //Optional\r + + \ \"description\": \"Withdrawal to personal wallet\" + //Optional\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/withdraw/1" + name: Get withdraw + meta: + id: req_b768c0d24c4b4cb68103c9157c096d9a + created: 1776615524638 + modified: 1776615524638 + isPrivate: false + description: "" + sortKey: -1776615518657 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/withdraw/search" + name: Search withdraw + meta: + id: req_e839064155a8437fae8feaaa3e66f485 + created: 1776615524639 + modified: 1776615524639 + isPrivate: false + description: "" + sortKey: -1776615518656 + method: POST + body: + mimeType: application/json + text: "{ //All fields are optional\r + + \ \"currency\": \"BTC\",\r + + \ \"destTxRef\": \"tx123456789\",\r + + \ \"destAddress\": + \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r + + \ \"status\": [\"CREATED\", \"PROCESSING\", \"CANCELED\", + \"REJECTED\", \"DONE\"]\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/withdraw/3/cancel" + name: Cancel withdraw + meta: + id: req_7d7e415b0eaa48a2884376b3f4477a52 + created: 1776615524640 + modified: 1776615524640 + isPrivate: false + description: "" + sortKey: -1776615518655 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/withdraw/search" + name: Admin search + meta: + id: req_3723e999d66a40cdbbb3fe04abc889ae + created: 1776615524641 + modified: 1776615524641 + isPrivate: false + description: "" + sortKey: -1776615518653 + method: POST + body: + mimeType: application/json + text: "{ //All fields are optional\r + + \ \"uuid\":\"some uuid\",\r + + \ \"currency\": \"BTC\",\r + + \ \"destTxRef\": \"tx123456789\",\r + + \ \"destAddress\": + \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r + + \ \"status\": [\"CREATED\", \"PROCESSING\", \"CANCELED\", + \"REJECTED\", \"DONE\"]\r + + }" + parameters: + - name: offset + value: "0" + disabled: false + - name: size + value: "10" + disabled: false + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/withdraw/2" + name: Admin get withdraw + meta: + id: req_8d7e0a7c011a475aa2a5341679bc24be + created: 1776615524641 + modified: 1776615524641 + isPrivate: false + description: "" + sortKey: -1776615518654 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/withdraw/2/process" + name: Admin process withdraw + meta: + id: req_cabfa416d86e4d7f8fbb1607499e698e + created: 1776615524642 + modified: 1776615524642 + isPrivate: false + description: "" + sortKey: -1776615518652 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/withdraw/2/reject" + name: Admin reject withdraw + meta: + id: req_d2274f2c2d9646d5a1d92992adc50305 + created: 1776615524643 + modified: 1776615524643 + isPrivate: false + description: "" + sortKey: -1776615518651 + method: POST + parameters: + - name: reason + value: Some reason + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/withdraw/5/accept" + name: Admin accept withdraw + meta: + id: req_e0bc2b56be104d0f85355c54b47fe273 + created: 1776615524644 + modified: 1776615524644 + isPrivate: false + description: "" + sortKey: -1776615518650 + method: POST + parameters: + - name: destTransactionRef + value: 0xsdf3j984fhe89fv834h893h + disabled: false + - name: destNote + value: "" + disabled: true + - name: destAmount + value: "" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Dashboard + meta: + id: fld_b6c1b983970c43d281f78964e601a437 + created: 1776615524650 + modified: 1776615524650 + sortKey: -1776615518642 + description: "" + children: + - url: "{{_['api-host']}}/v1/asset/tradeFee" + name: Fee For Symbol + meta: + id: req_1a17c66d2d914713adab8916fb999835 + created: 1776615524671 + modified: 1776615524671 + isPrivate: false + description: "" + sortKey: -1776615518619 + method: GET + parameters: + - name: symbol + value: TBTCTUSDT + disabled: false + - name: timestamp + value: "1" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['user-token']}}/v1/asset/getUserAsset" + name: User Assets + meta: + id: req_74436edeef5b426ba90777832b5a5b33 + created: 1776615524671 + modified: 1776615524671 + isPrivate: false + description: "" + sortKey: -1776615518618 + method: GET + parameters: + - name: symbol + value: TBTC + disabled: false + - name: quoteAsset + value: USDT + disabled: false + - name: calculateEvaluation + value: "true" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/asset/estimatedValue" + name: User Assets Estimated Value + meta: + id: req_d603aa47b06640bcb11ac7d6034385fd + created: 1776615524672 + modified: 1776615524672 + isPrivate: false + description: "" + sortKey: -1776615518617 + method: GET + parameters: + - name: quoteAsset + value: USDT + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/currencyInfo/quotes" + name: Quote currencies + meta: + id: req_877ecfcce6b14a99abf358a58b61324a + created: 1776615524673 + modified: 1776615524673 + isPrivate: false + description: "" + sortKey: -1776615518616 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/analytics/user-activity" + name: user-activity + meta: + id: req_ee8a355ddd3744e5983bea64063a90f4 + created: 1776615524674 + modified: 1776615524674 + isPrivate: false + description: "" + sortKey: -1776615518615 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Order + meta: + id: fld_372cab9706324ac79872b1a13c79fc0a + created: 1776615524651 + modified: 1776615524651 + sortKey: -1776615518641 + description: "" + children: + - url: "{{_['api-host']}}/v3/order" + name: Create Order + meta: + id: req_cd14c4b949d047b697d5c7c48fbd8051 + created: 1776615524652 + modified: 1776615524652 + isPrivate: false + description: "" + sortKey: -1776615518640 + method: POST + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: side + value: SELL + disabled: false + - name: type + value: LIMIT + disabled: false + - name: timeInForce + value: GTC + disabled: false + - name: timestamp + value: "1626805452" + disabled: false + - name: quantity + value: "0.01" + disabled: false + - name: price + value: "50000" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/order" + name: Cancel Order + meta: + id: req_6531663c67a24123b37063401acd9913 + created: 1776615524653 + modified: 1776615524653 + isPrivate: false + description: "" + sortKey: -1776615518639 + method: DELETE + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: timestamp + value: "1626805452" + disabled: false + - name: orderId + value: "2687" + disabled: false + - name: origClientOrderId + value: "" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Overview + meta: + id: fld_ff7bcad220eb41a092ddd01d32573d54 + created: 1776615524654 + modified: 1776615524654 + sortKey: -1776615518638 + description: "" + children: + - url: "{{_['api-host']}}/v3/ticker/24h" + name: 24h + meta: + id: req_839d4c351efa4012985af9a7a7e42ed1 + created: 1776615524655 + modified: 1776615524655 + isPrivate: false + description: "" + sortKey: -1776615518637 + method: GET + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: quote + value: USDT + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/ticker/24h" + name: 24h Copy + meta: + id: req_9170ee185a3743909afb0d15854eff80 + created: 1776615524656 + modified: 1776615524656 + isPrivate: false + description: "" + sortKey: -1776615518636 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/ticker/7d" + name: 7d + meta: + id: req_fca29198162d425ebc8ceb34a7c2dfd1 + created: 1776615524656 + modified: 1776615524656 + isPrivate: false + description: "" + sortKey: -1776615518635 + method: GET + parameters: + - name: symbol + value: TBTCTUSDT + disabled: false + - name: quote + value: TUSDT + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/ticker/1M" + name: 1m + meta: + id: req_6bd92a94291d48f1953c8d0ff691bcce + created: 1776615524657 + modified: 1776615524657 + isPrivate: false + description: "" + sortKey: -1776615518634 + method: GET + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: quote + value: USDT + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: OrderBook + meta: + id: fld_0878e595828841aab180baaace880b15 + created: 1776615524658 + modified: 1776615524658 + sortKey: -1776615518633 + description: "" + children: + - url: "{{_['api-host']}}/v3/depth" + name: Order Book + meta: + id: req_9813f74f83434a8d82788986121d0f87 + created: 1776615524658 + modified: 1776615524658 + isPrivate: false + description: "" + sortKey: -1776615518632 + method: GET + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: limit + value: "10" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: LastTrades + meta: + id: fld_99c33eb5ad314b5e98acf0eb9b6947c2 + created: 1776615524659 + modified: 1776615524659 + sortKey: -1776615518631 + description: "" + children: + - url: "{{_['api-host']}}/v3/trades" + name: Last Trades + meta: + id: req_f15fe75fe6984bb6bc59beaf9c83996f + created: 1776615524660 + modified: 1776615524660 + isPrivate: false + description: "" + sortKey: -1776615518630 + method: GET + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: limit + value: "100" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: MyOrder + meta: + id: fld_1083f85a1f82454296fb54fffdd371ce + created: 1776615524660 + modified: 1776615524660 + sortKey: -1776615518629 + description: "" + children: + - url: "{{_['api-host']}}/v3/openOrders" + name: All Orders + meta: + id: req_51da5e0273584dad8ee06fd61957bca8 + created: 1776615524661 + modified: 1776615524661 + isPrivate: false + description: "" + sortKey: -1776615518628 + method: GET + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: recvWindow + value: "1" + disabled: false + - name: timestamp + value: "1" + disabled: false + headers: + - name: Accept + value: application/json + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/myTrades" + name: Trades + meta: + id: req_64c393b9061445458af94e9abd2fd340 + created: 1776615524663 + modified: 1776615524663 + isPrivate: false + description: "" + sortKey: -1776615518627 + method: GET + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: startTime + value: "" + disabled: false + - name: endTime + value: "" + disabled: false + - name: timestamp + value: "1" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['user-token']}}/v3/order" + name: Query Order + meta: + id: req_b222f1ab127f4b7285428cd727c12631 + created: 1776615524664 + modified: 1776615524664 + isPrivate: false + description: "" + sortKey: -1776615518626 + method: GET + parameters: + - name: orderId + value: "30" + disabled: false + - name: symbol + value: BTCUSDT + disabled: false + - name: recvWindow + value: "1" + disabled: false + - name: timestamp + value: "1" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/openOrders" + name: Open Orders + meta: + id: req_5b1d36afd0a24b12a7466f897e8be987 + created: 1776615524665 + modified: 1776615524665 + isPrivate: false + description: "" + sortKey: -1776615518625 + method: GET + parameters: + - name: symbol + value: BTCUSDT + disabled: false + - name: recvWindow + value: "1" + disabled: false + - name: timestamp + value: "1" + disabled: false + headers: + - name: Accept + value: application/json + - name: Content-Type + value: application/x-www-form-urlencoded + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Market + meta: + id: fld_736a55d770224fbfa852dd38584951b6 + created: 1776615524665 + modified: 1776615524665 + sortKey: -1776615518624 + description: "" + children: + - url: "{{_['market-host']}}/v1/chart/spark-line" + name: Spark-line + meta: + id: req_cb9399cf31024070916790354d48e836 + created: 1776615524666 + modified: 1776615524666 + isPrivate: false + description: "" + sortKey: -1776615518623 + method: GET + body: + mimeType: application/json + text: "{\r + + \ \"symbols\":[\"BTC_USDT\", \"ETH_USDT\", + \"BTC_USDT\"],\r + + \ \"period\" : \"WEEKLY\"\r + + }" + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/ticker/price" + name: Price + meta: + id: req_4a469796d36841a69e08dd86bc09834c + created: 1776615524667 + modified: 1776615524667 + isPrivate: false + description: "" + sortKey: -1776615518622 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/exchangeInfo" + name: Exchange Info + meta: + id: req_7e4121de7b7f4407aff8713517b09df0 + created: 1776615524668 + modified: 1776615524668 + isPrivate: false + description: "" + sortKey: -1776615518621 + method: GET + parameters: + - name: symbol + value: "" + disabled: false + - name: symbols + value: "" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v3/currencyInfo" + name: Currency Info + meta: + id: req_152384de0ed44dc2b996ea7260da06f7 + created: 1776615524670 + modified: 1776615524670 + isPrivate: false + description: "" + sortKey: -1776615518620 + method: GET + parameters: + - name: currency + value: TUSDT + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Admin + meta: + id: fld_2aac192d51ec4128a8e2bc9aeaae4716 + created: 1776615524674 + modified: 1776615524674 + sortKey: -1776615518614 + description: "" + children: + - url: "{{_['auth-host']}}/auth/v1/user/impersonate" + name: Impersonate + meta: + id: req_701a41e6bca543588b007bc863c4ff66 + created: 1776615524675 + modified: 1776615524675 + isPrivate: false + description: "" + sortKey: -1776615518613 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"clientId\":\"web-app\",\r + + \ \"clientSecret\":\"7aba841f-f178-46ba-8b6d-6bd7d432115a\",\ + \r + + \ \"userId\":\"8b1e4016-25cb-4481-a315-2e854ae0f643\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" + name: Get Access Token + meta: + id: req_7c1ce81e2865453aae86ec222f1f4ea1 + created: 1776615524676 + modified: 1776615524676 + isPrivate: false + description: "" + sortKey: -1776615518612 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: client_id + value: web-app + disabled: false + - name: username + value: "{{_['admin-username']}}" + disabled: false + - name: password + value: "{{_['admin-password']}}" + disabled: false + - name: grant_type + value: password + disabled: false + - name: client_secret + value: "{{_['web-app-secret']}}" + disabled: false + - name: agent + value: postman + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/v1/user/0d510617-5505-4ed6-b6b8-b1df5a4ff784" + name: User Details + meta: + id: req_1bbd2f3b03ae4d0dab95e3e8bd30bb2d + created: 1776615524677 + modified: 1776615524677 + isPrivate: false + description: "" + sortKey: -1776615518611 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/v1/user" + name: List Auth Users + meta: + id: req_74962fa68a634f15b57f2c98e941d3e8 + created: 1776615524678 + modified: 1776615524678 + isPrivate: false + description: "" + sortKey: -1776615518610 + method: GET + parameters: + - name: offset + value: "1" + disabled: false + - name: size + value: "10" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/v1/group/kyc-accepted/members" + name: List Group Members + meta: + id: req_8e5c35cf5dc745a6a91e3b0f9db01d8d + created: 1776615524680 + modified: 1776615524680 + isPrivate: false + description: "" + sortKey: -1776615518609 + method: GET + parameters: + - name: offset + value: "0" + disabled: false + - name: size + value: "10" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['auth-host']}}/auth/v1/user/search" + name: Search Users + meta: + id: req_2f0c27c22792433d8d42d960b80feab4 + created: 1776615524681 + modified: 1776615524681 + isPrivate: false + description: "" + sortKey: -1776615518608 + method: GET + parameters: + - name: offset + value: "0" + disabled: false + - name: size + value: "10" + disabled: false + - name: search + value: demo1 + disabled: false + - name: by + value: email + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-token']}}/auth/v1/user/8b1e4016-25cb-4481-a315-2e854ae0f643/ky\ + c/accept" + name: User Accept KYC + meta: + id: req_65e4a3c3b0984d8bb43275c45cd13f54 + created: 1776615524681 + modified: 1776615524681 + isPrivate: false + description: "" + sortKey: -1776615518607 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-token']}}/auth/v1/user/24ab618d-9eaf-44f3-b506-83422416d4cb/ky\ + c/reject" + name: User Reject KYC + meta: + id: req_7a2a73f8cb7f49298fed23e5354be1c6 + created: 1776615524682 + modified: 1776615524682 + isPrivate: false + description: "" + sortKey: -1776615518606 + method: POST + parameters: + - name: reason + value: عکس ارسال شده با کارت ملی تطابق ندارد. + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-token']}}/auth/v1/user/0ba5fde2-8e93-4f5a-9d8d-ce6057adf2e7/ky\ + c/block" + name: User Block KYC + meta: + id: req_7c090c2be41b47d586e30278e85e2e02 + created: 1776615524683 + modified: 1776615524683 + isPrivate: false + description: "" + sortKey: -1776615518605 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-token']}}/auth/v1/user/8b1e4016-25cb-4481-a315-2e854ae0f643/jo\ + in-kyc" + name: User Join KYC Group + meta: + id: req_15707d5e1eff494a99f1fe9b4c03ecd9 + created: 1776615524685 + modified: 1776615524685 + isPrivate: false + description: "" + sortKey: -1776615518604 + method: POST + parameters: + - name: kycGroup + value: REQUESTED + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-host']}}/system/v1/currency" + name: Add Currency + meta: + id: req_75f0cb31e7c049f6bbe766650ab63e23 + created: 1776615524685 + modified: 1776615524685 + isPrivate: false + description: "" + sortKey: -1776615518603 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"name\":\"Solana\",\r + + \ \"symbol\":\"SOL\",\r + + \ \"precision\": 0.0001\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-host']}}/system/v1/currency/Solana" + name: Edit Currency + meta: + id: req_2d30b9a882244512aeb0a0ebee17913a + created: 1776615524686 + modified: 1776615524686 + isPrivate: false + description: "" + sortKey: -1776615518602 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"symbol\":\"SOLL\",\r + + \ \"precision\": 0.01\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-token']}}/system/v1/currency/Solana" + name: Delete Currency + meta: + id: req_1f35006d273440bebab6fedfabd8b511 + created: 1776615524687 + modified: 1776615524687 + isPrivate: false + description: "" + sortKey: -1776615518601 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/chain + name: Add New Chain + meta: + id: req_0b356d823d8a4d5a8b7218f172ec5ec1 + created: 1776615524688 + modified: 1776615524688 + isPrivate: false + description: "" + sortKey: -1776615518600 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"name\":\"ether-classic\",\r + + \ \"addressType\":\"ethereum\",\r + + \ \"scannerEndpoint\": null,\r + + \ \"scheduleDelaySeconds\": 600,\r + + \ \"scheduleErrorDelaySeconds\": 300\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/address/type + name: Add Address Type + meta: + id: req_3e2821d50a92479498783ea1a958cc9c + created: 1776615524688 + modified: 1776615524688 + isPrivate: false + description: "" + sortKey: -1776615518599 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"name\":\"solana\",\r + + \ \"addressRegex\":\".*\",\r + + \ \"memoRegex\":null\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/token + name: Add New Token + meta: + id: req_a1ff906db8074c89a6253877335b82b3 + created: 1776615524689 + modified: 1776615524689 + isPrivate: false + description: "" + sortKey: -1776615518598 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"symbol\":\"SHIB\",\r + + \ \"chain\":\"ethereum\",\r + + \ \"isToken\": true,\r + + \ \"tokenName\": \"Shiba\",\r + + \ \"tokenAddress\": + \"0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce\",\r + + \ \"withdrawFee\":0.1,\r + + \ \"minimumWithdraw\":100000000,\r + + \ \"isWithdrawEnabled\":true,\r + + \ \"decimal\":18\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/address/type + name: Get Address Types + meta: + id: req_2ebe27a597fd4dd2813d9780322f4801 + created: 1776615524690 + modified: 1776615524690 + isPrivate: false + description: "" + sortKey: -1776615518596 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/chain + name: Get Chains + meta: + id: req_a75c250ffc1d421f9e893bf5c01726fe + created: 1776615524690 + modified: 1776615524690 + isPrivate: false + description: "" + sortKey: -1776615518597 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/token + name: Get Tokens + meta: + id: req_59a059ced3194b988581329f0560636b + created: 1776615524691 + modified: 1776615524691 + isPrivate: false + description: "" + sortKey: -1776615518595 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/chain/ethereum-classic/endpoint + name: Set Chain Endpoint + meta: + id: req_b8c7e24c30d44833bd10cb5b05ec711e + created: 1776615524692 + modified: 1776615524692 + isPrivate: false + description: "" + sortKey: -1776615518594 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"url\":\"http://yomamasofat.com\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/chain/ethereum-classic/endpoint + name: Delete Chain Endpoint + meta: + id: req_71a2c9f1111c4867bcfda1a664ed9dfb + created: 1776615524693 + modified: 1776615524693 + isPrivate: false + description: "" + sortKey: -1776615518593 + method: DELETE + parameters: + - name: url + value: http://g.com + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-host']}}/system/v1/whitelist" + name: Get whitelist user + meta: + id: req_4239e4206e5a45e58e60095ee0c9d473 + created: 1776615524694 + modified: 1776615524694 + isPrivate: false + description: "" + sortKey: -1776615518592 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-host']}}/system/v1/whitelist" + name: Update whitelist user + meta: + id: req_4d13b5d67b3746ae8e125bf4aaf2bae6 + created: 1776615524695 + modified: 1776615524695 + isPrivate: false + description: "" + sortKey: -1776615518591 + method: POST + body: + mimeType: application/json + text: '{"data":["sara","sinnba"]}' + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-host']}}/system/v1/whitelist" + name: Delete whitelist user + meta: + id: req_1b65ba10d6944d4e83f50ae4f8e97b91 + created: 1776615524696 + modified: 1776615524696 + isPrivate: false + description: "" + sortKey: -1776615518590 + method: DELETE + body: + mimeType: application/json + text: '{"data":["sara"]}' + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/deposit/manually/0.00001_BTC/7440dffe-8332-477\ + 5-83c2-b5880c526c48" + name: Manual Deposit + meta: + id: req_7501ec53bc744c608813ad1a58816ffd + created: 1776615524697 + modified: 1776615524697 + isPrivate: false + description: "" + sortKey: -1776615518589 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"description\":\"test1\",\r + + \ \"ref\":\"test1\",\r + + \ \"gatewayUuid\":\"mag_f8b26943-4511-422d-8b5a-398b226815a2\ + \"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8095/admin/addresses + name: Add Addresses + meta: + id: req_6f1419e50e654061bcb87d35c40d959e + created: 1776615524698 + modified: 1776615524698 + isPrivate: false + description: "" + sortKey: -1776615518587 + method: POST + body: + mimeType: application/json + text: "// {\r + + // \"addresses\": [\"test1\", \"test2\", \"test3\"],\r + + // \"memos\": [\"memo1\", \"memo2\", null],\r + + // \"addressType\": \"ethereum\"\r + + // }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/deposit/manually/{amount}_{symbol}/{receiverUuid}" + name: Manual Deposit Copy + meta: + id: req_76fc87a7dd5e42fd88fb8f87ea285a4b + created: 1776615524698 + modified: 1776615524698 + isPrivate: false + description: "" + sortKey: -1776615518588 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"description\":\"test\",\r + + \ \"ref\":\"test\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-host']}}/v1/market/recent-trades" + name: Recent Trades + meta: + id: req_44ef6bdae46a493098bc1cf53d048360 + created: 1776615524699 + modified: 1776615524699 + isPrivate: false + description: "" + sortKey: -1776615518586 + method: GET + body: + mimeType: application/json + text: "{\r + + \"symbol\":\"BTC_USDT\",\r + + \"limit\" :10,\r + + \"offset\":0,\r + + // \"takerUuid\" : \"5669d02d-5be8-48a2-a985-67eb33bc309b\"\r + + \"excludeSelfTrade\" : false\r + + // \"makerUuid\" : \"5669d02d-5be8-48a2-a985-67eb33bc309b\"\r + + // \"fromDate\" :11111\r + + // \"toDate\" :11111\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/quotes" + name: Get quote currencies + meta: + id: req_8704beb5154e4847b805eef3e655cc7e + created: 1776615524700 + modified: 1776615524700 + isPrivate: false + description: "" + sortKey: -1776615518585 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/quote/USDT" + name: Update quote currency + meta: + id: req_f4362943a1a9476eb08cef50cd1fd73d + created: 1776615524701 + modified: 1776615524701 + isPrivate: false + description: "" + sortKey: -1776615518584 + method: PUT + parameters: + - name: isActive + value: "true" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/rate-limit" + name: Refresh Rate Limit + meta: + id: req_c9178e0c335c4563aca214e544a64019 + created: 1776615524702 + modified: 1776615524702 + isPrivate: false + description: "" + sortKey: -1776615518583 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Admin (new) + meta: + id: fld_f6933d1c8cff4ecb8817006ea972d6d7 + created: 1776615524702 + modified: 1776615524702 + sortKey: -1776615518582 + description: "" + children: + - name: Profile + meta: + id: fld_fa7b5ac4f18b45459d11c937aea4816e + created: 1776615524703 + modified: 1776615524703 + sortKey: -1776615518581 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/admin/profile/9ba9a448-354d-4c07-a432-1249871c4\ + 5b8" + name: Get Profile + meta: + id: req_1a103e7c6e3c472d813b2ea641345ad1 + created: 1776615524704 + modified: 1776615524704 + isPrivate: false + description: "" + sortKey: -1776615518579 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/profile" + name: Get Profiles + meta: + id: req_a77d5336c896434abb172898b5e09927 + created: 1776615524704 + modified: 1776615524704 + isPrivate: false + description: "" + sortKey: -1776615518580 + method: POST + body: + mimeType: application/json + text: "{\r + + \ //\"userId\": null, // optional\r + + \ //\"firstName\": null, // optional\r + + \ //\"lastName\": null, // optional\r + + \ //\"mobile\": null, // optional\r + + \ //\"email\": null, // optional\r + + \ //\"identifier\": null, // optional\r + + \ //\"nationality\": null, // optional (IRANAIN , + NON_IRANIAN)\r + + \ //\"gender\": null, // optional (FEMALE, MALE)\r + + \ //\"status\": null, // optional + (CREATED,CONTACT_INFO_COMPLETED,PROFILE_COMPLETED,SYSTEM_AP\ + PROVED,PENDING_ADMIN_APPROVAL,ADMIN_REJECTED,ADMIN_APPROVED)\ + \r + + \ //\"kycLevel\": null, // optional ( LEVEL_1, + LEVEL_2, LEVEL_3 )\r + + \ //\"createDateFrom\": null, // optional (timestamp)\r + + \ //\"createDateTo\": null, // optional (timestamp)\r + + \ \"limit\": 10, // (default 10)\r + + \ \"offset\": 0, // (default 0)\r + + \ \"ascendingByTime\": false // (default false)\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/profile/history/ec06fbc0-6041-48e3-b5f6-9\ + cd2ef57edb9" + name: Get Profile History + meta: + id: req_847dcd28bfb247088f1fe2b678f3dff1 + created: 1776615524705 + modified: 1776615524705 + isPrivate: false + description: "" + sortKey: -1776615518578 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/profile/approval-requests" + name: Get Approval Requests + meta: + id: req_20fb64953af84da6bafa6118948886ab + created: 1776615524706 + modified: 1776615524706 + isPrivate: false + description: "" + sortKey: -1776615518577 + method: POST + body: + mimeType: application/json + text: "{\r + + \ //\"userId\": null, // optional\r + + \ //\"status\": null, // optional (PENDING, + APPROVED, REJECTED)\r + + \ //\"createDateFrom\": null, // optional (timestamp)\r + + \ //\"createDateTo\": null, // optional (timestamp)\r + + \ \"limit\": 10, // (default 10)\r + + \ \"offset\": 0, // (default 0)\r + + \ \"ascendingByTime\": false // (default false)\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/profile/approval-request/7" + name: Get Approval Request + meta: + id: req_bac7466c1b4d4cae9b8916f5a5fc3033 + created: 1776615524706 + modified: 1776615524706 + isPrivate: false + description: "" + sortKey: -1776615518576 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/profile/approval-request" + name: Update Approval Request + meta: + id: req_536340206f9f4f15b56a92f54825c7bb + created: 1776615524707 + modified: 1776615524707 + isPrivate: false + description: "" + sortKey: -1776615518575 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"id\": 2,\r + + \ \"description\": \"test\", // optional\r + + \ \"status\": \"REJECTED\" //(APPROVED, REJECTED)\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Transactions + meta: + id: fld_e1dcc1b014e24203a01d8317af8ae26e + created: 1776615524708 + modified: 1776615524708 + sortKey: -1776615518574 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/admin/transactions/summary" + name: Get User Transaction Summary + meta: + id: req_2fac7fc3653e4804a47dca75e15dabc9 + created: 1776615524709 + modified: 1776615524709 + isPrivate: false + description: "" + sortKey: -1776615518573 + method: POST + body: + mimeType: application/json + text: "{\r + + \ //\"userId\": null, // optional\r + + \ //\"currency\": null, // optional\r + + \ //\"sourceSymbol\": null, // optional\r + + \ //\"destSymbol\": null, // optional\r + + \ //\"category\": null, // optional + (TRADE,DEPOSIT,DEPOSIT_TO,WITHDRAW_FROM,WITHDRAW,FEE,SWAP,R\ + EFERRAL_COMMISSION,REFERRAL_KYC_REWARD,REFERENT_COMMISSION,\ + KYC_ACCEPTED_REWARD,SYSTEM)\r + + \ //\"startTime\": null, // optional (timestamp)\r + + \ //\"endTime\": null, // optional (timestamp)\r + + \ \"limit\": 10, // (default 10)\r + + \ \"offset\": 0, // (default 0)\r + + \ \"ascendingByTime\": false // (default false)\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/transactions/deposits" + name: Get Deposit Transactions + meta: + id: req_180b3e07076e4baea88f6d44458be169 + created: 1776615524710 + modified: 1776615524710 + isPrivate: false + description: "" + sortKey: -1776615518572 + method: POST + body: + mimeType: application/json + text: "{\r + + \ //\"uuid\": null, // optional\r + + \ //\"currency\": null, // optional\r + + \ //\"sourceAddress\": null, // optional\r + + \ //\"transactionRef\": null, // optional\r + + \ //\"startTime\": null, // optional (timestamp)\r + + \ //\"endTime\": null, // optional (timestamp)\r + + \ //\"status\": [], // optional, list of + (PROCESSING, DONE, INVALID)\r + + \ \"limit\": 10, // (default 10)\r + + \ \"offset\": 0, // (default 0)\r + + \ \"ascendingByTime\": false // (default false)\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/transactions/withdraws" + name: Get Withdraw Transactions + meta: + id: req_d7a58e47bf904f2ebbf7a96733971b8c + created: 1776615524711 + modified: 1776615524711 + isPrivate: false + description: "" + sortKey: -1776615518571 + method: POST + body: + mimeType: application/json + text: "{\r + + \ // \"withdrawUuid\" : + \"764dfa79-cab4-403c-8526-049a80f13b69\", // optional\r + + \ //\"uuid\": null, // optional\r + + \ //\"currency\": null, // optional\r + + \ //\"destTxRef\": null, // optional\r + + \ //\"destAddress\": null, // optional\r + + \ //\"startTime\": null, // optional (timestamp)\r + + \ //\"endTime\": null, // optional (timestamp)\r + + \ //\"status\": [], // optional, list of + (REQUESTED,CREATED,ACCEPTED,CANCELED,REJECTED,DONE)\r + + \ \"limit\": 10, // (default 10)\r + + \ \"offset\": 0, // (default 0)\r + + \ \"ascendingByTime\": false // (default false)\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/transactions/swaps" + name: Get Swap Transactions + meta: + id: req_a6227b83ac0144a5bff49b972bb728e2 + created: 1776615524712 + modified: 1776615524712 + isPrivate: false + description: "" + sortKey: -1776615518570 + method: POST + body: + mimeType: application/json + text: "{\r + + \ //\"userId\": null, // optional\r + + \ //\"sourceSymbol\": null, // optional\r + + \ //\"destSymbol\": null, // optional\r + + \ //\"startTime\": null, // optional (timestamp)\r + + \ //\"endTime\": null, // optional (timestamp)\r + + \ \"limit\": 10, // (default 10)\r + + \ \"offset\": 0, // (default 0)\r + + \ \"ascendingByTime\": false, // (default false)\r + + \ \"status\" :\"Committed\" //(Created, Expired, Committed) + defualt = Committed\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/transactions/trades" + name: Get Trade Transactions Copy + meta: + id: req_18ab4cf87c744a62b317c52c0338c497 + created: 1776615524713 + modified: 1776615524713 + isPrivate: false + description: "" + sortKey: -1776615518569 + method: POST + body: + mimeType: application/json + text: "{\r + + \ //\"coin\": null, // optional\r + + \ //\"startTime\": null, // optional (timestamp)\r + + \ //\"endTime\": null, // optional (timestamp)\r + + \ \"limit\": 10, // (default 10)\r + + \ \"offset\": 0, // (default 0)\r + + \ \"ascendingByTime\": false // (default false)\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Wallet + meta: + id: fld_718b5feaa3744cc0b31866e3f4f08a68 + created: 1776615524715 + modified: 1776615524715 + sortKey: -1776615518568 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/admin/wallet/users" + name: Get Users Wallets + meta: + id: req_076bd7e7d27e45bab4fd6cac85987597 + created: 1776615524716 + modified: 1776615524716 + isPrivate: false + description: "" + sortKey: -1776615518567 + method: GET + parameters: + - name: uuid + value: "" + disabled: false + - name: currency + value: "" + disabled: false + - name: excludeSystem + value: "" + disabled: false + - name: limit + value: "10" + disabled: false + - name: offset + value: "0" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/wallet/system/total" + name: Get System Wallet Total + meta: + id: req_6fef8a73d32a405e9dfdc1368743d17a + created: 1776615524716 + modified: 1776615524716 + isPrivate: false + description: "" + sortKey: -1776615518566 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/wallet/users/total" + name: Get User Wallet Total + meta: + id: req_9f30b4048efa4f0c999c1ca174890a86 + created: 1776615524717 + modified: 1776615524717 + isPrivate: false + description: "" + sortKey: -1776615518565 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Withdraw + meta: + id: fld_901c082a80c44df3b50f4fcbeb04d881 + created: 1776615524718 + modified: 1776615524718 + sortKey: -1776615518564 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/admin/withdraw/manually/20_USDT/dcb7c726-8e0e-4\ + 0ba-a8c7-5a017905176d" + name: Withdraw Manually + meta: + id: req_43387134b36c40b0b7c7907cafa8a95f + created: 1776615524719 + modified: 1776615524719 + isPrivate: false + description: "" + sortKey: -1776615518563 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"description\":\"It is not nullable\",\r + + \ \"ref\":\"12345678999009\",\r + + \ \"attachment\":\"test\",\r + + \ \"gatewayUuid\":\"mag_f8ebdc5f-585f-4694-974c-9a29543d\ + 4a2b\"\r + + }" + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/withdraw/23b7c726-8e0e-40ba-a8c7-5a017905\ + 176d/done" + name: Done Withdraw + meta: + id: req_b422c98c2d74416587ae3ed8e5b82bcd + created: 1776615524720 + modified: 1776615524720 + isPrivate: false + description: "" + sortKey: -1776615518561 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"destTransactionRef\":\"0xsdf3j984fhe89fv834h893h\",\r + + \ \"destNote\":\"hi\",\r + + \ \"destAmount\":null,\r + + \ \"attachment\":\"test\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/withdraw/23b7c726-8e0e-40ba-a8c7-5a017905\ + 176d/accept" + name: Accept Withdraw + meta: + id: req_bcd236bb44ec403e894190a5721c74a9 + created: 1776615524720 + modified: 1776615524720 + isPrivate: false + description: "" + sortKey: -1776615518562 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/admin/withdraw/23b7c726-8e0e-40ba-a8c7-5a017905\ + 176d/reject" + name: Reject Withdraw + meta: + id: req_fafa4d87e1ce45b2960476e37074ddc4 + created: 1776615524721 + modified: 1776615524721 + isPrivate: false + description: "" + sortKey: -1776615518560 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"reason\":\"invalid address\",\r + + \ \"attachment\":\"test\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Deposit + meta: + id: fld_2b4a88e64f4141d5a186230d5c594fd5 + created: 1776615524722 + modified: 1776615524722 + sortKey: -1776615518559 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/admin/deposit/manually/20_USDT/dcb7c726-8e0e-40\ + ba-a8c7-5a017905176d" + name: Deposit Manually + meta: + id: req_21144d44c8c445298c63063c3c661118 + created: 1776615524723 + modified: 1776615524723 + isPrivate: false + description: "" + sortKey: -1776615518558 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"description\":\"test2\",\r + + \ \"ref\":\"123456988754483\",\r + + \ \"attachment\":\"test\",\r + + \ \"gatewayUuid\":\"mag_f8ebdc5f-585f-4694-974c-9a29543d\ + 4a2b\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Localization + meta: + id: fld_4bae2de52e4f48778491fb576c613736 + created: 1776948978232 + modified: 1778083336480 + sortKey: -1776948978232 + description: "" + children: + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/391f2f22-d6e1-4b08-9f30-ad1872ac14c\ + 0/localization" + name: Save Terminal Localozation + meta: + id: req_5f4586d3f3c449df96decdc0851f1923 + created: 1776768190645 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1776949037652 + method: POST + body: + mimeType: application/json + text: |- + [ + { + "description": "test 2", + "owner": "test 2", + "language": "EN" + }, + { + "description": "تست ۲", + "owner": "تست ۲", + "language": "FA" + } + ] + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/391f2f22-d6e1-4b08-9f30-ad1872ac14c\ + 0/localization" + name: Get Terminal Localization + meta: + id: req_50ea9123489d4be887b1e9d26168c491 + created: 1776768350923 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1776949037752 + method: GET + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] }}/opex/v1/admin/terminal/localization/24" + name: Delete Terminal Localization + meta: + id: req_05bfb23535e2435284be0cd855ffe6de + created: 1776768439323 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1776949037852 + method: DELETE + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] }}/opex/v1/admin/currency/IRT/localization" + name: Get Currency Localization + meta: + id: req_658103b61e454b46a4bf980da1d97081 + created: 1776949144966 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1776949144966 + method: GET + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] }}/opex/v1/admin/currency/IRT/localization" + name: Save Currency Localization + meta: + id: req_644cc832abd4497cb92b2d6cfa665951 + created: 1776949259843 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1776949091459 + method: POST + body: + mimeType: application/json + text: |- + [ + { + "name": "تومان", + "title": "تومان", + "alias": "ریال", + "description": "ارز ایران", + "shortDescription": "ارز ", + "language": "FA" + }, + { + "name": "toman", + "title": "toman", + "alias": "toman", + "description": "toman", + "shortDescription": "toman", + "language": "EN" + } + ] + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] }}/opex/v1/admin/currency/localization/22" + name: Delete currency localization + meta: + id: req_1b62c1077e7b4606a03b9d36e533e67a + created: 1776949318083 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1776949051328.75 + method: PUT + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4e596e2\ + 9cc7/localization" + name: Save Gateway Localization + meta: + id: req_b188873d030c4a388ccf6a269a52609e + created: 1777735868520 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777735868520 + method: POST + body: + mimeType: application/json + text: |- + [ + { + "depositDescription": "گیت وی", + "withdrawDescription": "گیت وی", + "language":"FA" + } + ] + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4e596e2\ + 9cc7/localization" + name: Get Gateway Localization + meta: + id: req_d6c262f9b46f49e7bd1fefd1621d9cc8 + created: 1777735910142 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777735910142 + method: GET + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4e596e2\ + 9cc7/localization/2" + name: Delete Gateway Localization + meta: + id: req_3c92884a9b644112a946d9e494b15cd7 + created: 1777735941100 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777735941100 + method: DELETE + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Terminal & Gateway + meta: + id: fld_2fdedb573d38479c9abe20f37b025bbc + created: 1777893915002 + modified: 1778083336480 + sortKey: -1777893915002 + description: "" + children: + - url: "{{ _['api-host'] }}/opex/v1/admin/terminal" + name: Save Terminal + meta: + id: req_1460445827d64fa9b23e2fe9dca73231 + created: 1777893920101 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777893920101 + method: POST + body: + mimeType: application/json + text: |- + { + "owner": "فاطمه ایمانی ور", + "identifier": "5057851017634988", + "active": true, + "type": "CARD", + "metaData": "izb", + "description": "Valid For 1 Day", + "displayOrder": 1 + } + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ + c" + name: Update Terminal + meta: + id: req_1b6fafd29afb47a2815f0a2bf62c2155 + created: 1777894228030 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777874172725.875 + method: PUT + body: + mimeType: application/json + text: |- + { + "owner": "فاطمه ایمانی ور", + "identifier": "5057851017634988", + "active": true, + "type": "CARD", + "metaData": "izb", + "description": "Valid For 1 Day", + "displayOrder": 1 + } + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ + c" + name: Delete Terminal + meta: + id: req_7a1a2d85f5ad4adf8f3ab3e03048dd25 + created: 1777894267178 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777856893772.6406 + method: DELETE + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ + c" + name: Get Terminal + meta: + id: req_c3e805c1450843128fed3b792e257b0f + created: 1777894298007 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777864299038.3125 + method: GET + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] }}/opex/v1/admin/terminal" + name: Get Terminals + meta: + id: req_8e2f73ac76f245a88d66e9271d7d98f3 + created: 1777894318403 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777859362194.5312 + method: GET + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ + c/gateway" + name: Get Gateway Terminal + meta: + id: req_96838e5f4c6b49beb75cbc0b63e4f977 + created: 1777894363527 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777893920126 + method: GET + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/gateway/aadfa3e2-3f94-41cc-b53c-967\ + ded4f0dpo" + name: Assign Terminal To Gateway + meta: + id: req_252425572ad641cfbccb29664d13628f + created: 1777894401365 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777854425350.75 + method: POST + body: + mimeType: application/json + text: '["e360a8cb-a594-486c-a221-5be94d1e122b","gh360cb-a594-486c-a881-5be94d1emmm"]' + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/terminal/gateway/aadfa3e2-3f94-41cc-b53c-967\ + ded4f0dpo" + name: Revoke Terminal From Gateway + meta: + id: req_06490d89ca1b40e486022698e938eff6 + created: 1777894500460 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777834677975.625 + method: DELETE + body: + mimeType: application/json + text: '["e360a8cb-a594-486c-a221-5be94d1e122b","gh360cb-a594-486c-a881-5be94d1emmm"]' + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/currency/gateway" + name: Get Gateways + meta: + id: req_a350d09ac9564e05b90b2895fcd0a463 + created: 1777894610657 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777893920201 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/gateway/e360a8cb-a594-486c-a221-5be94d1e\ + 122b/terminal" + name: "Get Terminal Gateway " + meta: + id: req_8359bedf3865476b8c378088c4bc396d + created: 1777894705788 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777893920113.5 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] }}/opex/v1/admin/BTC/gateway" + name: Add Currency To Gateway + meta: + id: req_5be974c7827341d581fea4619c8f80f7 + created: 1777894821253 + modified: 1778083336480 + isPrivate: false + description: |- + { + "type": "OffChain", // Card2card, Sheba, IPG + "depositMin": 0.1, + "depositMax": 10, + "withdrawMin": 2, + "withdrawMax": 5, + "isActive": true, + "withdrawFee": 0.001, + "withdrawAllowed": false, + "depositAllowed": true, + "displayOrder" : 1 + + "transferMethod": "IPG" + } + { + "type": "OnChain", + "depositMin": 0.1, + "depositMax": 10, + "withdrawMin": 2, + "withdrawMax": 5, + "isActive": true, + "withdrawFee": 0.001, + "withdrawAllowed": false, + "depositAllowed": false, + "tokenName": null, + "tokenAddress": null, + "implementationSymbol": "tes444489998899ggh", + "isToken": false, + "decimal": 18, + "chain": "test-bitcoin", + "displayOrder" : 1 + + } + sortKey: -1777893920301 + method: POST + body: + mimeType: application/json + text: |- + { + "type": "OnChain", + "depositMin": 0.1, + "depositMax": 10, + "withdrawMin": 2, + "withdrawMax": 5, + "isActive": true, + "withdrawFee": 0.001, + "withdrawAllowed": false, + "depositAllowed": false, + "tokenName": null, + "tokenAddress": null, + "implementationSymbol": "tes44dassa99ggh", + "isToken": false, + "decimal": 18, + "chain": "test-bitcoin", + "displayOrder" : 1 + + } + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/BTC/gateway/e360a8cb-a594-486c-a221-5be94d1e\ + 122b" + name: Update Gateway + meta: + id: req_5fcfcd705c634e22bb344a09ab8eecb7 + created: 1777895166941 + modified: 1778083336480 + isPrivate: false + description: |- + { + "type": "OffChain", // Card2card, Sheba, IPG + "depositMin": 0.1, + "depositMax": 10, + "withdrawMin": 2, + "withdrawMax": 5, + "isActive": true, + "withdrawFee": 0.001, + "withdrawAllowed": false, + "depositAllowed": true, + "displayOrder" : 1 + + "transferMethod": "IPG" + } + { + "type": "OnChain", + "depositMin": 0.1, + "depositMax": 10, + "withdrawMin": 2, + "withdrawMax": 5, + "isActive": true, + "withdrawFee": 0.001, + "withdrawAllowed": false, + "depositAllowed": false, + "tokenName": null, + "tokenAddress": null, + "implementationSymbol": "tes444489998899ggh", + "isToken": false, + "decimal": 18, + "chain": "test-bitcoin", + "displayOrder" : 1 + + } + sortKey: -1777893920251 + method: PUT + body: + mimeType: application/json + text: |- + { + "type": "OnChain", + "depositMin": 0.1, + "depositMax": 10, + "withdrawMin": 2, + "withdrawMax": 5, + "isActive": true, + "withdrawFee": 0.001, + "withdrawAllowed": false, + "depositAllowed": false, + "tokenName": null, + "tokenAddress": null, + "implementationSymbol": "tes44dassa99ggh", + "isToken": false, + "decimal": 18, + "chain": "test-bitcoin", + "displayOrder" : 1 + + } + headers: + - name: Content-Type + value: application/json + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/BTC/gateway/e360a8cb-a594-486c-a221-5be94d1e\ + 122b" + name: Get Gateway + meta: + id: req_30fdabfe534f48ce99f90387b17c5288 + created: 1777895205056 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777893920176 + method: GET + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{ _['api-host'] + }}/opex/v1/admin/BTC/gateway/e360a8cb-a594-486c-a221-5be94d1e\ + 122b" + name: Delete Gateway + meta: + id: req_bc75f9f9cc5d4652a5de7004062ac332 + created: 1777895318852 + modified: 1778083336480 + isPrivate: false + description: "" + sortKey: -1777893920151 + method: DELETE + headers: + - name: User-Agent + value: insomnia/12.5.0 + description: "" + disabled: false + authentication: + type: bearer + token: "{{ _['admin-token'] }}" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Profile + meta: + id: fld_a6e07a1838b34abda78e52114a202d34 + created: 1776615524724 + modified: 1776615524724 + sortKey: -1776615518557 + description: "" + children: + - url: https://api.opex.dev:8443/auth/realms/opex/user-profile + name: Get Attributes + meta: + id: req_02be52f319904bb980b308395f4f4fae + created: 1776615524756 + modified: 1776615524756 + isPrivate: false + description: "" + sortKey: -1776615518522 + method: GET + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtWlJ1S0w3UW1ibEYyNm8yNXp3MnNaanRqYTB1RkZrVnJQLVJlTUtpTmw4In0.eyJleHAiOjE2NTExMDE4MzMsImlhdCI6MTY1MTA2NTgzMywianRpIjoiN2ZjYmZhNjktMzM5ZC00OWY3LWEzNzMtZDk3NGQ0NTdiMjMyIiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjBmMDBiMWMxLTcyODMtNGY2Ny1hZDFmLTkzMjI3MTJhZDljNyIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZTFiOGM2NjAtY2U1NC00ODFmLTlmNzktZDhkYTU5ZmE4ZDBjIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2K3Ys9uM2YYg2KfYqNmI2KfZhNit2LPZhtuMIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGVtbzFAb3BleC5kZXYiLCJnaXZlbl9uYW1lIjoi2K3Ys9uM2YYiLCJmYW1pbHlfbmFtZSI6Itin2KjZiNin2YTYrdiz2YbbjCIsImVtYWlsIjoiZGVtbzFAb3BleC5kZXYifQ.MtvaH4D8NUDUFQLJcH1vI2x-3HOtnHqImaMvXdvAnrMjuQo6kZRzi0G_K7-jr3pYM39BJP6m25AqvyIWkn8bH8ctD-e_eKILohNnnBdDttzqTxBkc4ozWo5ELHj8-FBJgmdASXY0FKT2yTTeFSDy8bK-I1xTx1LU438J3BaRIhIp6O0zx58Vw_82iUfMgyP_u_p1NFh1Si04DHD42fGgWLPreflUY64DTTmr2WZ7kgzg45N3R7twDMfkGCXlqSRWLmquok0n9SH9REhUYq16BvoKXTBWiux4wYZRhL2wZIqba6EV1WgiC9uiHU5biQCv3wvw1jxkPOvfNd-rhdn83A + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev:8443/auth/realms/opex/user-profile + name: Add Attributes + meta: + id: req_6245034796544502a9f2f0bd601eb90b + created: 1776615524757 + modified: 1776615524757 + isPrivate: false + description: "" + sortKey: -1776615518521 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"firstNameEn\":\"a\",\r + + \ \"lastNameEn\":\"b\",\r + + \ \"firstName\":\"حسین\",\r + + \ \"lastName\":\"b\",\r + + \ \"birthdayJ\":\"01/06/1375\",\r + + \ \"birthdayG\":\"22/08/1996\",\r + + \ \"nationalId\":\"111111111\",\r + + \ \"passportNumber\":\"sfcdfvdfvxc\",\r + + \ \"mobile\":\"09383381451\",\r + + \ \"telephone\":\"02133253214\",\r + + \ \"postalCode\":\"1718614644\",\r + + \ \"residence\":\"\",\r + + \ \"nationality\":\"\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtWlJ1S0w3UW1ibEYyNm8yNXp3MnNaanRqYTB1RkZrVnJQLVJlTUtpTmw4In0.eyJleHAiOjE2NTExMDE4MzMsImlhdCI6MTY1MTA2NTgzMywianRpIjoiN2ZjYmZhNjktMzM5ZC00OWY3LWEzNzMtZDk3NGQ0NTdiMjMyIiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjBmMDBiMWMxLTcyODMtNGY2Ny1hZDFmLTkzMjI3MTJhZDljNyIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZTFiOGM2NjAtY2U1NC00ODFmLTlmNzktZDhkYTU5ZmE4ZDBjIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2K3Ys9uM2YYg2KfYqNmI2KfZhNit2LPZhtuMIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGVtbzFAb3BleC5kZXYiLCJnaXZlbl9uYW1lIjoi2K3Ys9uM2YYiLCJmYW1pbHlfbmFtZSI6Itin2KjZiNin2YTYrdiz2YbbjCIsImVtYWlsIjoiZGVtbzFAb3BleC5kZXYifQ.MtvaH4D8NUDUFQLJcH1vI2x-3HOtnHqImaMvXdvAnrMjuQo6kZRzi0G_K7-jr3pYM39BJP6m25AqvyIWkn8bH8ctD-e_eKILohNnnBdDttzqTxBkc4ozWo5ELHj8-FBJgmdASXY0FKT2yTTeFSDy8bK-I1xTx1LU438J3BaRIhIp6O0zx58Vw_82iUfMgyP_u_p1NFh1Si04DHD42fGgWLPreflUY64DTTmr2WZ7kgzg45N3R7twDMfkGCXlqSRWLmquok0n9SH9REhUYq16BvoKXTBWiux4wYZRhL2wZIqba6EV1WgiC9uiHU5biQCv3wvw1jxkPOvfNd-rhdn83A + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev:8443/auth/realms/opex/user-profile/kyc/status + name: KYC Status + meta: + id: req_446f5249c75d499b99c9a2d77f42df80 + created: 1776615524758 + modified: 1776615524758 + isPrivate: false + description: "" + sortKey: -1776615518520 + method: GET + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiajc2MUtyM2U4cl9LUEZjU19VRGtHNUFTN2szcGNJd1FiNmFqX3RoaTEwIn0.eyJleHAiOjE2NTI4NjYxOTksImlhdCI6MTY1Mjc3OTc5OSwianRpIjoiN2ZhNjNiZTEtMDgxOC00M2NlLWExZjktNzFiZDhhMWZiZTJkIiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6ImRlMTdhMmNmLTg3ZGItNDAwZi04Yjc5LTRlYjg1MWNlMjkwZSIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiNjUyNTQ3ODAtZmY4NS00YTBlLWExMWMtODU0YTAwNDk2ZDEyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2qnYp9ix2KjYsSDZhtmF2KfbjNi024wiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJkZW1vMUBvcGV4LmRldiIsImdpdmVuX25hbWUiOiLaqdin2LHYqNixIiwiZmFtaWx5X25hbWUiOiLZhtmF2KfbjNi024wiLCJlbWFpbCI6ImRlbW8xQG9wZXguZGV2In0.R2jpuGAJwtspDm6mIxG4ts7N-DrlMGixU63PGBL_FfaL7q-hUcyi5rnFe-xGVa-EfrfGzuPfWW5O_WRHbM9YiBvfuKEgELbfi9GYY86GJyqHZ7qPE1MB8T-zglPD48oSYTYv8HhbsN1g6DNkVNrex6k0Dp8C5jVwjwChew8SPE3d86gzHCL4l4X3vqG-aonoyjmE37CResDYwtiklK9mmuk3I-ji1xjdmHpVkEtWw0DBlX2TRfNpo9G1M-uqPySeDe3gkIYuakx899uREcnXpMVxRc3aqXN6_XtiS7jSyKhYTWxVneNIxnyE1i-YkaEB4riPFM0_wmToYvmGFnPBOg + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev:8443/auth/realms/opex/user-profile/kyc + name: KYC Image Paths + meta: + id: req_27b427f80506494a9eabbf6c116d7f47 + created: 1776615524759 + modified: 1776615524759 + isPrivate: false + description: "" + sortKey: -1776615518519 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"selfiePath\":\"/0d510617-5505-4ed6-b6b8-b1df5a4ff784/70e\ + a5067.png\",\r + + \ \"idCardPath\":\"/0d510617-5505-4ed6-b6b8-b1df5a4ff784/70e\ + a5068.png\",\r + + \ \"acceptFormPath\":\"/0d510617-5505-4ed6-b6b8-b1df5a4ff784\ + /70ea5069.png\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtWlJ1S0w3UW1ibEYyNm8yNXp3MnNaanRqYTB1RkZrVnJQLVJlTUtpTmw4In0.eyJleHAiOjE2NTEzNDAyMDksImlhdCI6MTY1MTMwNDIwOSwianRpIjoiMGE4YzQ1MjMtMjliYy00MjA0LTkxYmYtNGU1NDZjMmI2OGY0IiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjBmMDBiMWMxLTcyODMtNGY2Ny1hZDFmLTkzMjI3MTJhZDljNyIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiYzhiMmQyNWEtNGVjYi00NTk3LWJjYzItMTU5ZmViYWIwODkyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2qnYp9ix2KjYsSDZhtmF2KfbjNi024wg24zaqdmFIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGVtbzFAb3BleC5kZXYiLCJnaXZlbl9uYW1lIjoi2qnYp9ix2KjYsSDZhtmF2KfbjNi024wiLCJmYW1pbHlfbmFtZSI6ItuM2qnZhSIsImVtYWlsIjoiZGVtbzFAb3BleC5kZXYifQ.pS5yJNGDsXGXjXPC7eGrryW79S1jvqzBezuUo6DRQy19qEJBAfAjlArNFZgf--Pucii9sj08KVqrzA5C0fHCFRydb42PNuj04WtquxBllifUWj77ycw3skA4u9m5s4jlpJvCXgQFC2oMcNP405e7999eGUKxpcI6tCdA4917shAylWyoGrSKVY5BpQ1_W7gSKk0HeLCciqnqwM3og9N1LQomWXeZcjGl0UtaOpCC52IWMp5yM_WEw5UrhKM4Du7nOI5v7Nq2S8t6c4JIYZLwvqcGLyAe1ZZGQSKADkyNwoelbCsXMTOqUQOJgB4_XgggonUJpQCkg2_3csPLLU4Zww + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: v2 + meta: + id: fld_d96b1e84fff44a1899cde30bb304a56a + created: 1776615524725 + modified: 1776615524725 + sortKey: -1776615518556 + description: "" + children: + - name: user + meta: + id: fld_c7e41b315d6e44319d99df33d1c8955c + created: 1776615524726 + modified: 1776615524726 + sortKey: -1776615518555 + description: "" + children: + - url: localhost:8079/v2/profile + name: Update profile + meta: + id: req_96ec572d0fe74771b59bd6ff31e117c5 + created: 1776615524726 + modified: 1776615524726 + isPrivate: false + description: "" + sortKey: -1776615518554 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"firstName\": \"fatemeh\",\r + + \ \"lastName\": \"imanipour\",\r + + \ \"address\": \"tehran\",\r + + \ \"telephone\": \"7733445566\",\r + + \ \"postalCode\": \"169876543\",\r + + \ \"nationality\": \"iranian\",\r + + \ \"identifier\": \"0019002602\",\r + + \ \"gender\": \"Female\",\r + + \ \"mobile\": \"09905135295\",\r + + \ \"birthDate\": \"2020-06-15T00:00:00\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/profile/linked-account + name: Add linked bank account + meta: + id: req_d8993c30b8294cd6b6cb1725d7fd6d3c + created: 1776615524727 + modified: 1776615524727 + isPrivate: false + description: "" + sortKey: -1776615518553 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"bankAccountType\":\"Sheba\",\r + + \ \"number\":\"480690011980901162627001\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/profile/linked-account + name: Get linked bank account + meta: + id: req_2de7aa45c42b4f9a97955ca5715a932d + created: 1776615524728 + modified: 1776615524728 + isPrivate: false + description: "" + sortKey: -1776615518552 + method: GET + body: + mimeType: application/json + text: "{\r + + \ \"bankAccountType\":\"Sheba\",\r + + \ \"number\":\"480690011980901162627001\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/profile/linked-account/b9fc8d36-60f9-4c91-807f-3205201f6fa + name: update linked account(enable,disable) + meta: + id: req_56c326653fa04f7f96674542e04cd114 + created: 1776615524729 + modified: 1776615524729 + isPrivate: false + description: "" + sortKey: -1776615518551 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"status\":\"Disable\" //Enable\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/admin/profile/limitation + name: Get limitation + meta: + id: req_64378484383641199eff5d6141893270 + created: 1776615524731 + modified: 1776615524731 + isPrivate: false + description: "" + sortKey: -1776615518550 + method: GET + body: + mimeType: multipart/form-data + params: + - name: action + value: CashOut + disabled: true + type: text + - name: userId + value: 27396a77-797c-47c4-b2cb-4a8e5c9034fd + disabled: true + type: text + - name: size + value: "3" + disabled: true + type: text + - name: offset + value: "2" + disabled: true + type: text + - name: reason + value: MajorProfileChange + disabled: true + type: text + - name: groupBy + value: reason + disabled: true + type: text + headers: + - name: Content-Type + value: multipart/form-data + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/profile/linked-account/b9fc8d36-60f9-4c91-807f-3205201f6faf + name: Delete linked account + meta: + id: req_ea6c4e8bb1f74dadb54badcefcfa7ef5 + created: 1776615524731 + modified: 1776615524731 + isPrivate: false + description: "" + sortKey: -1776615518549 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: https://api.opex.dev/profile/v2/profile + name: Get profile + meta: + id: req_bd2ad7d9e7614ce587a32f9202b0958a + created: 1776615524733 + modified: 1776615524733 + isPrivate: false + description: "" + sortKey: -1776615518548 + method: GET + authentication: + type: bearer + disabled: false + token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NTI5NDIzNzQsImlhdCI6MTc1MjkzODc3NCwianRpIjoiN2VkMDlhY2YtYTFkNC00ZDQxLTg4YWUtNDhjNWQ1ZDY2MTA1IiwiaXNzIjoiaHR0cDovL2tjLm9wZXguZGV2OjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJvcGV4LWFwaS1rZXkiLCJzdWIiOiIwMGVlYTRiZi0xOWJkLTRhODQtOGQ2NS0xMzY2ZTRmYTcxYTkiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiOWNhMDMxYTAtZTNiZS00MTBmLWJhNWQtZGNiNTM0YTI1MzQyIiwic2NvcGUiOiJ0cnVzdCIsImZpcnN0TmFtZSI6IkFtaXIiLCJsYXN0TmFtZSI6IlJhamFiaSIsInBlcm1pc3Npb25zIjpbImRlcG9zaXQ6d3JpdGUiLCJvcmRlcjp3cml0ZSIsImFkZHJlc3M6YXNzaWduIiwiZGVwb3NpdDp3cml0ZSJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJkZWZhdWx0LXJvbGVzLW9wZXgiLCJ1c2VyIl0sIm1vYmlsZSI6IjA5OTgxMzkwOTA5IiwidXNlcm5hbWUiOiIwOTk4MTM5MDkwOSJ9.UPmGazBmuK1IqJW_mFoRbDSehMF9yLK34jUBhdkvf_ytdRKhzrkPouVpG9ITTtN7WkZJFfx0Tv-_4FmXCv1NSiBQDkX10bVT5THWXiMuhAWk1QT2-xWQYCR656q-VMcJ8S_6GPE7rD-k4zrd0J02t8ZTYF9dMvPsHqqmA_griY24kG9AtGePmqQl53Ul-jaGfMUnixNmz613PGXWNrybGBGUz0DwGNRsxoNbWcJwqfHZ3ZT-vDOVr7JwPau3_P2KSEWc7DkgB5qg7TWSeJ5VPn4aLaL8HnrM8kL1Aql16ByYbWnqqYlNNAR07ER6AwQsIrZ6-iPgIlpDXwJ8mTAx1w + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: admin + meta: + id: fld_cff1106c35f346e0b406a4db18d31824 + created: 1776615524733 + modified: 1776615524733 + sortKey: -1776615518547 + description: "" + children: + - url: localhost:8079/v2/profile + name: Update profile + meta: + id: req_a0be82791bef463abcb5a7ee9d62e885 + created: 1776615524734 + modified: 1776615524734 + isPrivate: false + description: "" + sortKey: -1776615518546 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"firstName\": \"fatemeh\",\r + + \ \"lastName\": \"imanipour\",\r + + \ \"address\": \"tehran\",\r + + \ \"telephone\": \"7733445566\",\r + + \ \"postalCode\": \"169876543\",\r + + \ \"nationality\": \"iranian\",\r + + \ \"identifier\": \"0019002602\",\r + + \ \"gender\": \"Female\",\r + + \ \"mobile\": \"09905135295\",\r + + \ \"birthDate\": \"2020-06-15T00:00:00\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/admin/profile/history/27396a77-797c-47c4-b2cb-4a8e5c9034fd + name: Get profile history + meta: + id: req_361674d9ad5946afbded6f482b234f8e + created: 1776615524735 + modified: 1776615524735 + isPrivate: false + description: "" + sortKey: -1776615518545 + method: GET + body: + mimeType: application/json + text: "{\r + + \ \"firstName\": \"fatemeh\",\r + + \ \"lastName\": \"imanipour\",\r + + \ \"address\": \"tehran\",\r + + \ \"telephone\": \"7733445566\",\r + + \ \"postalCode\": \"169876543\",\r + + \ \"nationality\": \"iranian\",\r + + \ \"identifier\": \"0019002602\",\r + + \ \"gender\": \"Female\",\r + + \ \"mobile\": \"09905135295\",\r + + \ \"birthDate\": \"2020-06-15T00:00:00\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/admin/profile/linked-account/verify/a4d85bd2-cc50-4b01-9e43-4511a4a738fa + name: Verify an account + meta: + id: req_0a98a443d20543a4bc45613ef0093e81 + created: 1776615524736 + modified: 1776615524736 + isPrivate: false + description: "" + sortKey: -1776615518543 + method: PUT + body: + mimeType: application/json + text: "{\"description\":\"beautiful name\",\r + + \"verified\":true}" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/admin/profile/linked-account/history/a4d85bd2-cc50-4b01-9e43-4511a4a738fa + name: Get history of an account + meta: + id: req_f6aae0efb0af45ac96da6a73d0d45e9a + created: 1776615524736 + modified: 1776615524736 + isPrivate: false + description: "" + sortKey: -1776615518544 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "" + name: Set limitations + meta: + id: req_fd8a7a2675a2436287ad515cd5af3cf3 + created: 1776615524737 + modified: 1776615524737 + isPrivate: false + description: "" + sortKey: -1776615518542 + method: POST + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/admin/profile/limitation + name: Get limitation + meta: + id: req_c3cddc1a021646118791e4d917a6e2cd + created: 1776615524738 + modified: 1776615524738 + isPrivate: false + description: "" + sortKey: -1776615518541 + method: GET + body: + mimeType: multipart/form-data + params: + - name: action + value: CashOut + disabled: true + type: text + - name: userId + value: 27396a77-797c-47c4-b2cb-4a8e5c9034fd + disabled: true + type: text + - name: size + value: "3" + disabled: true + type: text + - name: offset + value: "2" + disabled: true + type: text + - name: reason + value: MajorProfileChange + disabled: true + type: text + - name: groupBy + value: reason + disabled: true + type: text + headers: + - name: Content-Type + value: multipart/form-data + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8079/v2/admin/profile/limitation/history + name: Get limitation history + meta: + id: req_ff6e994b657e43b3a10b6a99ca28b834 + created: 1776615524739 + modified: 1776615524739 + isPrivate: false + description: "" + sortKey: -1776615518540 + method: GET + body: + mimeType: multipart/form-data + params: + - name: action + value: CashOut + disabled: true + type: text + - name: userId + value: All + disabled: true + type: text + - name: size + value: "3" + disabled: true + type: text + - name: offset + value: "2" + disabled: true + type: text + headers: + - name: Content-Type + value: multipart/form-data + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['admin-host']}}/admin/v2/profile" + name: get Profile + meta: + id: req_e5a961ca3e4745de9e0311b4a4171164 + created: 1776615524740 + modified: 1776615524740 + isPrivate: false + description: "" + sortKey: -1776615518539 + method: POST + body: + mimeType: application/json + text: "{\r + + \"includeLimitation\":true,\r + + \"includeLinkedAccount\":true,\r + + \"partialSearch\":true,\r + + \"userId\":\"27\",\r + + \"firstName\":\"fate\",\r + + \"lastName\":\"imani\",\r + + \"nationalCode\":\"0019\",\r + + \"email\":\"imanipour\",\r + + \"createDateFrom\":\"2023-08-22T14:36:06\",\r + + \"createDateTo\":\"2023-08-23T14:36:06\",\r + + \"mobile\":\"09\"//,\r + + //\"accountNumber\":\"\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Completion + meta: + id: fld_409b7373d99347d09aca78b949cd5f2f + created: 1776615524741 + modified: 1776615524741 + sortKey: -1776615518538 + description: "" + children: + - url: "{{_['profile-host']}}/approval-request" + name: Get Profile Approval Request + meta: + id: req_4d27f2a8e47442f0bb2d1a837407b518 + created: 1776615524742 + modified: 1776615524742 + isPrivate: false + description: "" + sortKey: -1776615518536 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/personal-data" + name: Get Profile + meta: + id: req_fe99b7bc8a6741c7b147afbf7172a435 + created: 1776615524742 + modified: 1776615524742 + isPrivate: false + description: "" + sortKey: -1776615518537 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/contact/update/otp-request" + name: Request Update(email or mobile) + meta: + id: req_72ffeed4f2364a26b988b759253990fc + created: 1776615524743 + modified: 1776615524743 + isPrivate: false + description: "" + sortKey: -1776615518535 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"mobile\" : \"09212880961\"\r + + \ // \"email\" : \"amir@gmail.com\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/contact/update/otp-verification" + name: Verify Update(email or mobile) + meta: + id: req_3cca58962d694458b7369bd4928e4cda + created: 1776615524744 + modified: 1776615524744 + isPrivate: false + description: "" + sortKey: -1776615518534 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ // \"email\" : \"amir@gmail.com\"\r + + \ \"mobile\" : \"09212880961\",\r + + \ \"otpCode\" :\"612354\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/completion" + name: Completion + meta: + id: req_99caf67a0c4846f29dfcba4f7c9a8be0 + created: 1776615524745 + modified: 1776615524745 + isPrivate: false + description: "" + sortKey: -1776615518533 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"firstName\": \"امیر\",\r + + \ \"lastName\": \"رجبی\",\r + + \ \"address\": \"tehran\",\r + + \ // \"telephone\": \"7733445566\",\r + + \ // \"postalCode\": \"169876543\",\r + + \ \"nationality\": \"IRANIAN\", + // IRANIAN,NON_IRANIAN\r + + \ \"identifier\": \"0025018108\",\r + + \ \"gender\": \"MALE\",\r + + \ \"birthDate\": \"2002-06-29T00:00:00\"\r + + }" + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Bank Account + meta: + id: fld_b53eb74719ec427aa668d571a662a0bb + created: 1776615524746 + modified: 1776615524746 + sortKey: -1776615518532 + description: "" + children: + - url: "{{_['profile-host']}}/bank-account" + name: Add bank account + meta: + id: req_058775e477004b9ca076b7385adcc8b0 + created: 1776615524747 + modified: 1776615524747 + isPrivate: false + description: "" + sortKey: -1776615518531 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"name\" : \"amir\",\r + + \ // \"cardNumber\" : \"5057851031070300\"\r + + \ \"iban\" : \"IR560690016783002286017001\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/bank-account" + name: Get all bank account + meta: + id: req_beaf3b7a30cc421697d01fddba6db29f + created: 1776615524748 + modified: 1776615524748 + isPrivate: false + description: "" + sortKey: -1776615518530 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/bank-account/8" + name: Delete bank account + meta: + id: req_8be6236e594841f7a5171e35132732fb + created: 1776615524749 + modified: 1776615524749 + isPrivate: false + description: "" + sortKey: -1776615518529 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/bank-account/ownership" + name: Validate ownership ( for ipg ) + meta: + id: req_e73c4a8a68af4bcb95befacaba6f2bbf + created: 1776615524750 + modified: 1776615524750 + isPrivate: false + description: "" + sortKey: -1776615518528 + method: GET + parameters: + - name: cardNumber + value: "6219861902618981" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Address Book + meta: + id: fld_00b9e73e9d034259ac993a72329f5980 + created: 1776615524751 + modified: 1776615524751 + sortKey: -1776615518527 + description: "" + children: + - url: "{{_['profile-host']}}/address-book" + name: Get all address book items + meta: + id: req_df56036e5b3c4aa1930e3c24d68eee67 + created: 1776615524752 + modified: 1776615524752 + isPrivate: false + description: "" + sortKey: -1776615518526 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/address-book" + name: Save address book item + meta: + id: req_50c277c1ba7a4a1780d127b98d392ab7 + created: 1776615524753 + modified: 1776615524753 + isPrivate: false + description: "" + sortKey: -1776615518525 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"name\" : \"tes2t\",\r + + \ \"address\" : \"test31234\",\r + + \ \"addressType\" : \"BCS\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/address-book/8" + name: Delete address book item + meta: + id: req_951e6f23fda54e27a8ceaa080fb4d5de + created: 1776615524754 + modified: 1776615524754 + isPrivate: false + description: "" + sortKey: -1776615518524 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['profile-host']}}/address-book/3" + name: Update Address book item + meta: + id: req_983c7e04052c4763b797d9c432a663eb + created: 1776615524755 + modified: 1776615524755 + isPrivate: false + description: "" + sortKey: -1776615518523 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"name\" : \"testtest\",\r + + \ \"address\" : \"test123445\",\r + + \ \"addressType\" : \"BCS\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Landing + meta: + id: fld_4193c9540f744ccd922f29b0651895a7 + created: 1776615524759 + modified: 1776615524759 + sortKey: -1776615518518 + description: "" + children: + - url: "{{_['api-host']}}/v1/landing/marketStats" + name: Market stats + meta: + id: req_7392f312f59040a6b26fe14dd8811f92 + created: 1776615524760 + modified: 1776615524760 + isPrivate: false + description: "" + sortKey: -1776615518517 + method: GET + parameters: + - name: interval + value: 24H + disabled: false + - name: limit + value: "10" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/landing/exchangeInfo" + name: Exchange info + meta: + id: req_a40deb7301c3454dbabdf62011d99dbb + created: 1776615524761 + modified: 1776615524761 + isPrivate: false + description: "" + sortKey: -1776615518516 + method: GET + parameters: + - name: interval + value: 3M + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/v1/landing/globalPrices" + name: Global prices + meta: + id: req_0b674c1c4009486fa25d1d5eaa77db1f + created: 1776615524762 + modified: 1776615524762 + isPrivate: false + description: "" + sortKey: -1776615518515 + method: GET + parameters: + - name: usdSymbol + value: TUSDT + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: kyc + meta: + id: fld_af696082669141c4913956f5f324d4d4 + created: 1776615524763 + modified: 1776615524763 + sortKey: -1776615518514 + description: "" + children: + - name: user + meta: + id: fld_cb97863390f14db09fc456e0c16e50af + created: 1776615524764 + modified: 1776615524764 + sortKey: -1776615518513 + description: "" + children: + - url: localhost:8078/v2/kyc/upload + name: Upload images for level2 + meta: + id: req_df22cb319b394212accafb929f27e0ae + created: 1776615524765 + modified: 1776615524765 + isPrivate: false + description: "" + sortKey: -1776615518512 + method: POST + body: + mimeType: multipart/form-data + params: + - name: files + disabled: false + fileName: /C:/Users/imani/Downloads/fatemeh_idcard2 (1).jpeg + type: file + headers: + - name: Content-Type + value: multipart/form-data + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "" + name: Get user's kyc steps + meta: + id: req_bc9a440dcab244b3a5dc876e80e6b4b1 + created: 1776615524766 + modified: 1776615524766 + isPrivate: false + description: "" + sortKey: -1776615518511 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "" + name: Get details of step + meta: + id: req_8c42a980784a4a2992a175a328e4dd07 + created: 1776615524767 + modified: 1776615524767 + isPrivate: false + description: "" + sortKey: -1776615518510 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: admin + meta: + id: fld_fedb76c031cd4a8581df220537547aa5 + created: 1776615524768 + modified: 1776615524768 + sortKey: -1776615518509 + description: "" + children: + - url: localhost:8078/v2/admin/kyc/review/a1840f95-d542-4754-afda-c0bb8e3cabeb + name: Review uploaded files + meta: + id: req_40ca686e99f04f709d673ffe6c68ca4d + created: 1776615524768 + modified: 1776615524768 + isPrivate: false + description: "" + sortKey: -1776615518508 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"status\":\"Accepted\", //Rejected\r + + \ \"description\":\"Beautiful Image\",\r + + \ \"userId\":\"d8c107ee-5f23-496a-9d96-8646fd535d36\"\r + + }\r\n" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8078/v2/admin/kyc/d8c107ee-5f23-496a-9d96-8646fd535d36 + name: Update kyc level manually + meta: + id: req_33b7bb1058c546db97ec4ebd8787c4ad + created: 1776615524769 + modified: 1776615524769 + isPrivate: false + description: "" + sortKey: -1776615518507 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"level\":\"ManualUpdateLevel1\", + //ManualUpdateLevel2\r + + \ \"description\":\"ugly Image\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8078/v2/admin/kyc/step + name: Get Users' kyc steps + meta: + id: req_063d2b5f1d8c4f488cd88e81d9bef02b + created: 1776615524770 + modified: 1776615524770 + isPrivate: false + description: "" + sortKey: -1776615518506 + method: GET + body: + mimeType: multipart/form-data + params: + - name: userId + value: d8c107ee-5f23-496a-9d96-8646fd535d36 + disabled: true + type: text + - name: status + value: Accepted + disabled: true + type: text + - name: step + value: Register + disabled: true + type: text + headers: + - name: Content-Type + value: multipart/form-data + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "" + name: Get details of step + meta: + id: req_b314a4c0bbdc469a932656553aacba20 + created: 1776615524771 + modified: 1776615524771 + isPrivate: false + description: "" + sortKey: -1776615518505 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: localhost:8078/v2/admin/kyc/history/626e9cef-c91e-4ba8-927e-5a186f4f14be + name: Get history of users' kyc level + meta: + id: req_c98ad332b4fc4f388ddcbc2040f32931 + created: 1776615524772 + modified: 1776615524772 + isPrivate: false + description: "" + sortKey: -1776615518504 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Config + meta: + id: fld_0660ffa98d1c4f1982dac2e16cd9958f + created: 1776615524773 + modified: 1776615524773 + sortKey: -1776615518503 + description: "" + children: + - url: "{{_['config-host']}}/user/v1" + name: Get user config + meta: + id: req_3e7d0bbe48284e93b76874668ff35887 + created: 1776615524774 + modified: 1776615524774 + isPrivate: false + description: "" + sortKey: -1776615518502 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/user/v1/pair" + name: Add pairs + meta: + id: req_8b5ffcb395984dfb9ddd7d80ff512085 + created: 1776615524775 + modified: 1776615524775 + isPrivate: false + description: "" + sortKey: -1776615518500 + method: POST + body: + mimeType: application/json + text: '["BTCUSDT", "ETHUSDT"]' + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/user/v1" + name: Update user config + meta: + id: req_bba0959e4dab418b919b2fa3e5c5d3e8 + created: 1776615524775 + modified: 1776615524775 + isPrivate: false + description: "" + sortKey: -1776615518501 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"theme\": \"dark\",\r + + \ \"language\": \"en\",\r + + \ \"favoritePairs\": [\"BTCUSDT\"]\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/user/v1/pair" + name: Remove pairs + meta: + id: req_f2637bc858b546ad8fc5d939c1794284 + created: 1776615524776 + modified: 1776615524776 + isPrivate: false + description: "" + sortKey: -1776615518499 + method: DELETE + body: + mimeType: application/json + text: '["ETHUSDT"]' + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/web/v1" + name: Get system config + meta: + id: req_846e2e5b249b49adbcdc6e851faa6d1d + created: 1776615524777 + modified: 1776615524777 + isPrivate: false + description: "" + sortKey: -1776615518498 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/web/v1" + name: Update system config + meta: + id: req_358c8c13d36d4dc0bb46b9bb52902a5b + created: 1776615524778 + modified: 1776615524778 + isPrivate: false + description: "" + sortKey: -1776615518497 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"logoUrl\": \"logo/url\",\r + + \ \"title\": \"Opex\",\r + + \ \"description\": \"Open Source Exchange\",\r + + \ \"defaultLanguage\": \"fa\",\r + + \ \"supportedLanguages\": [\"fa\",\"en\",\"uzb\"],\r + + \ \"defaultTheme\": \"DARK\",\r + + \ \"supportEmail\": \"hi@opex.co\",\r + + \ \"baseCurrency\": \"USDT\",\r + + \ \"dateType\": \"Jalali\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/web/v1" + name: Update system config Copy + meta: + id: req_4fdec1101afe4d6a80fc41d466f9b308 + created: 1776615524779 + modified: 1776615524779 + isPrivate: false + description: "" + sortKey: -1776615518496 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"logoUrl\": \"logo/url\",\r + + \ \"title\": \"Opex\",\r + + \ \"description\": \"Open Source Exchange\",\r + + \ \"defaultLanguage\": \"fa\",\r + + \ \"supportedLanguages\": [\"fa\",\"en\",\"uzb\"],\r + + \ \"defaultTheme\": \"DARK\",\r + + \ \"supportEmail\": \"hi@opex.co\",\r + + \ \"baseCurrency\": \"TUSDT\",\r + + \ \"dateType\": \"Jalali\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/user-level/v1" + name: Get user level config + meta: + id: req_23fdd438c5484375ac9f600f8c37a023 + created: 1776615524780 + modified: 1776615524780 + isPrivate: false + description: "" + sortKey: -1776615518495 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/user-level/v1" + name: Post/update user level config + meta: + id: req_b39dce4463cf4fc3939f1b72d62cfe76 + created: 1776615524781 + modified: 1776615524781 + isPrivate: false + description: "" + sortKey: -1776615518494 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"userLevel\": \"LEVEL_1\",\r + + \ \"name\": \"پایه\",\r + + \ \"description\": \"با تکمیل پروفایل و تایید اطلاعات + هویتی\",\r + + \ \"onChainDepositAllowed\": true,\r + + \ \"offChainDepositAllowed\": true,\r + + \ \"onChainWithdrawAllowed\": false,\r + + \ \"offChainWithdrawAllowed\": true\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['config-host']}}/user-level/v1/LEVEL_1" + name: Delete user level config + meta: + id: req_68f3b3fdaf9242d7af3d7320bc8e4127 + created: 1776615524782 + modified: 1776615524782 + isPrivate: false + description: "" + sortKey: -1776615518493 + method: DELETE + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Transaction history + meta: + id: fld_8116b719c79244f28ac3cdd39de45779 + created: 1776615524783 + modified: 1776615524783 + sortKey: -1776615518492 + description: "" + children: + - url: "{{_['market-host']}}/v1/user/tx/{{_['user-uuid']}}/history" + name: Buy and Sell + meta: + id: req_2fabdda11cba46849094e8f7d07a66fc + created: 1776615524783 + modified: 1776615524783 + isPrivate: false + description: "" + sortKey: -1776615518491 + method: POST + body: + mimeType: application/json + text: "\r + + \ { \"startTime\": null,\r + + \ \"endTime\": null,\r + + \ \"limit\": 200,\r + + \ \"offset\": 0,\r + + \ \"ascendingByTime\":false}" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/v1/deposit/history" + name: Deposit + meta: + id: req_47d5e3a47fdf468c8fad54fc8a81e5c1 + created: 1776615524784 + modified: 1776615524784 + isPrivate: false + description: "" + sortKey: -1776615518490 + method: POST + body: + mimeType: application/json + text: "{ // All fields are optional\r + + \ \"currency\": \"BTC\",\r + + \ \"startTime\": 1622505600,\r + + \ \"endTime\": 1625097600,\r + + \ \"limit\": 10,\r + + \ \"offset\": 0,\r + + \ \"ascendingByTime\": false\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/withdraw/history" + name: Withdraw + meta: + id: req_acbedb955494484e89e5c0151eafcc18 + created: 1776615524785 + modified: 1776615524785 + isPrivate: false + description: "" + sortKey: -1776615518489 + method: POST + body: + mimeType: application/json + text: "{ // All fields are optional\r + + \ \"currency\": \"BTC\",\r + + \ \"startTime\": 1622505600,\r + + \ \"endTime\": 1625097600,\r + + \ \"limit\": 10,\r + + \ \"offset\": 0,\r + + \ \"ascendingByTime\": false\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/v2/transaction" + name: Transaction history + meta: + id: req_c844afeb2b4543e8b5b99727274dd945 + created: 1776615524786 + modified: 1776615524786 + isPrivate: false + description: "" + sortKey: -1776615518488 + method: POST + body: + mimeType: application/json + text: "{ // All fields are optional\r + + \ \"currency\": \"BTC\",\r + + \ \"category\": \"TRADE\", // [TRADE, DEPOSIT, WITHDRAW, FEE, + SYSTEM]\r + + \ \"startTime\": 1622505600,\r + + \ \"endTime\": 1625097600,\r + + \ \"limit\": 10,\r + + \ \"offset\": 0,\r + + \ \"ascendingByTime\": false\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Referral + meta: + id: fld_72c6f326b84341e29cbca14024c5001a + created: 1776615524787 + modified: 1776615524787 + sortKey: -1776615518487 + description: "" + children: + - name: Code + meta: + id: fld_4a06a669d5834faf9dda5d4b2303599f + created: 1776615524787 + modified: 1776615524787 + sortKey: -1776615518486 + description: "" + children: + - url: "{{_['referral-host']}}/codes" + name: Generate Referral Code + meta: + id: req_9ccc1d593b8f4a9b985e8118f9de47b6 + created: 1776615524789 + modified: 1776615524789 + isPrivate: false + description: "" + sortKey: -1776615518485 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"uuid\" :\"1aac31a5-0443-44ed-aaf2-0022e85e1027\" ,\r + + \ \"commissionShare\" :\"STEP_4\" // STEP_1 , // STEP_2 + , // STEP_3 , // STEP_4\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['referral-host']}}/codes/10001" + name: Get Referral Code Info + meta: + id: req_b09fcabc2bb44982ae23377987f3ce2f + created: 1776615524790 + modified: 1776615524790 + isPrivate: false + description: "" + sortKey: -1776615518484 + method: GET + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['referral-host']}}/codes" + name: Get All Referral Codes + meta: + id: req_9fbea7ae46ad41f6b156cc6036349f8c + created: 1776615524791 + modified: 1776615524791 + isPrivate: false + description: "" + sortKey: -1776615518483 + method: GET + parameters: + - name: uuid + value: 1aac31a5-0443-44ed-aaf2-0022e85e1027 + disabled: false + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['referral-host']}}/codes/10002" + name: Delete Referral Code + meta: + id: req_fe971099a2a445bca28dee893928a18a + created: 1776615524792 + modified: 1776615524792 + isPrivate: false + description: "" + sortKey: -1776615518482 + method: DELETE + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Checkout + meta: + id: fld_f7a3fda72fd04d178c60583ddbe94d20 + created: 1776615524792 + modified: 1776615524792 + sortKey: -1776615518481 + description: "" + children: + - url: "{{_['referral-host']}}/checkouts/checkout-all" + name: Checkout All Rewards + meta: + id: req_881986a08a5f4be2b5e075f8d2ccdd92 + created: 1776615524793 + modified: 1776615524793 + isPrivate: false + description: "" + sortKey: -1776615518480 + method: POST + parameters: + - name: category + value: REFERRAL_COMMISSION + disabled: false + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['referral-host']}}/checkouts" + name: Get All Checkouts By Status + meta: + id: req_cb8efe4389594738aa87706f11bf63ea + created: 1776615524794 + modified: 1776615524794 + isPrivate: false + description: "" + sortKey: -1776615518479 + method: GET + parameters: + - name: status + value: CHECKED_OUT + disabled: false + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Config + meta: + id: fld_1e4e226b60454d9e91e73e377157b790 + created: 1776615524795 + modified: 1776615524795 + sortKey: -1776615518478 + description: "" + children: + - url: "{{_['referral-host']}}/configs" + name: Get Config + meta: + id: req_8dca19d89bce4506aa9ccb9d6d6aa0d6 + created: 1776615524797 + modified: 1776615524797 + isPrivate: false + description: "" + sortKey: -1776615518477 + method: GET + parameters: + - name: name + value: default + disabled: false + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Reference + meta: + id: fld_a047678c93734a8b9d14464b72bb680e + created: 1776615524798 + modified: 1776615524798 + sortKey: -1776615518476 + description: "" + children: + - url: "{{_['referral-host']}}/references/" + name: Get Referral Code's References + meta: + id: req_83719f86437c4972b3525b6219728c59 + created: 1776615524799 + modified: 1776615524799 + isPrivate: false + description: "" + sortKey: -1776615518474 + method: GET + parameters: + - name: uuid + value: 13cb32d1-f7f6-4d40-b33b-0d725fe3a2f4 + disabled: false + - name: code + value: "10000" + disabled: false + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['referral-host']}}/references/assign" + name: Assign Referrer + meta: + id: req_fb497dc8f2254bd88c9b03a0bfb93095 + created: 1776615524799 + modified: 1776615524799 + isPrivate: false + description: "" + sortKey: -1776615518475 + method: POST + parameters: + - name: uuid + value: 1aac31a5-0443-44ed-aaf2-0022e85e1027 + disabled: true + - name: code + value: "10000" + disabled: false + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Report + meta: + id: fld_28307ea76d5a428e8ba3924075e23fef + created: 1776615524800 + modified: 1776615524800 + sortKey: -1776615518473 + description: "" + children: + - url: "{{_['referral-host']}}/reports/1aac31a5-0443-44ed-aaf2-0022e85e1027" + name: Get Report By Uuid + meta: + id: req_e56863982cb24cf4bbca1cada0f9cf93 + created: 1776615524801 + modified: 1776615524801 + isPrivate: false + description: "" + sortKey: -1776615518472 + method: GET + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Reward + meta: + id: fld_f164894e6c654d96be729036bc5a0b97 + created: 1776615524802 + modified: 1776615524802 + sortKey: -1776615518471 + description: "" + children: + - url: "{{_['referral-host']}}/rewards" + name: Get Rewards + meta: + id: req_c52440fb93e34beb8d7ea67a1e30e9d4 + created: 1776615524803 + modified: 1776615524803 + isPrivate: false + description: "" + sortKey: -1776615518470 + method: GET + parameters: + - name: referentUuid + value: 1aac31a5-0443-44ed-aaf2-0022e85e1027 + disabled: true + - name: rewardedUuid + value: 13cb32d1-f7f6-4d40-b33b-0d725fe3a2f4 + disabled: false + - name: code + value: "10000" + disabled: true + authentication: + type: bearer + disabled: false + token: "" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Currency + meta: + id: fld_c01289d2912745f9a2c8bdfb58203707 + created: 1776615524803 + modified: 1776615524803 + sortKey: -1776615518469 + description: "" + children: + - url: "{{_['wallet-host']}}/currency" + name: Get Currencies List (with their gateways) + meta: + id: req_43a5115842784773b56510f01c763e38 + created: 1776615524817 + modified: 1776615524817 + isPrivate: false + description: "" + sortKey: -1776615518454 + method: GET + body: + mimeType: application/x-www-form-urlencoded + params: + - name: includeManualGateways + value: "true" + disabled: false + - name: includeOffChainGateways + value: "true" + disabled: false + - name: includeOnChainGateways + value: "true" + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/BTC" + name: Get Specific currency (with it's gateway) + meta: + id: req_a5cc0090b4b54aab8503fe1ff27a97ac + created: 1776615524818 + modified: 1776615524818 + isPrivate: false + description: "" + sortKey: -1776615518453 + method: GET + body: + mimeType: multipart/form-data + parameters: + - name: includeManualGateways + value: "true" + disabled: false + - name: includeOffChainGateways + value: "true" + disabled: false + - name: includeOnChainGateways + value: "true" + disabled: false + headers: + - name: Content-Type + value: multipart/form-data + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/IRT" + name: Update A Currency + meta: + id: req_ec235a66a3174017adb6ea3fff3b6f22 + created: 1776615524818 + modified: 1776615524818 + isPrivate: false + description: "" + sortKey: -1776615518452 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"symbol\": \"IRT\",\r + + \ \"uuid\": \"152a24a0-1d34-4149-996b-0bcd2c3a0c6a\",\r + + \ \"name\": \"Toman\",\r + + \ \"precision\": 0.0,\r + + \ \"title\": null,\r + + \ \"alias\": \"تومان\",\r + + \ \"icon\": + \"https://exky.io/storage/img/cryptocurrency-icons/irt.svg\",\r + + \ \"isTransitive\": false,\r + + \ \"isActive\": true,\r + + \ \"sign\": \"IRT\",\r + + \ \"description\": null,\r + + \ \"shortDescription\": null,\r + + \ \"withdrawAllowed\": false,\r + + \ \"depositAllowed\": false,\r + + \ \"externalUrl\": null,\r + + \ \"gateways\": null,\r + + \ \"availableGatewayType\": null,\r + + \ \"order\": 3,\r + + \ \"systemBalance\": null\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency" + name: Create New Currency + meta: + id: req_d0fe9e202a2b4be5a69856000b35fce4 + created: 1776615524819 + modified: 1776615524819 + isPrivate: false + description: "" + sortKey: -1776615518451 + method: POST + body: + mimeType: application/json + text: "\r + + \r + + {\"symbol\": \"IRT\",\r + + \"name\": \"Toman\",\r + + \"precision\": 0,\r + + \"title\": null,\r + + \"alias\": \"تومان\",\r + + \"icon\": + \"https://exky.io/storage/img/cryptocurrency-icons/irt.svg\",\r + + \"isTransitive\": false,\r + + \"isActive\": true,\r + + \"sign\": \"IRT\",\r + + \"description\": null,\r + + \"shortDescription\": null,\r + + \"externalUrl\": null,\r + + \"order\": 3,\r + + \"systemBalance\": 100000000\r + + \r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Gateways + meta: + id: fld_55e5ac1554b141be8ff802e9a520170f + created: 1776615524804 + modified: 1776615524804 + sortKey: -1776615518468 + description: "" + children: + - url: "{{ _['api-host'] }}/opex/v1/admin/IRT/gateway" + name: Create OffChain Gateway + meta: + id: req_08c3f75819e94c638c957f69e158511c + created: 1776615524805 + modified: 1778345831212 + isPrivate: false + description: "" + sortKey: -1776615518467 + method: POST + body: + mimeType: application/json + text: |- + { + "type": "OffChain", + "currencySymbol":"IRT", + "depositMin": 50000, + "depositMax": 10000000, + "withdrawMin": 50000, + "withdrawMax": 10000000, + "withdrawFee": 10000, + "withdrawAllowed": true, + "depositAllowed": true, + "isDepositActive": true, + "isWithdrawActive": true, + "transferMethod": "SHEBA" + } + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['bc-gateway-host']}}/crypto-currency/gateways" + name: Get All Gateways + meta: + id: req_676a3ce67e604c4d93443e0ae396380d + created: 1776615524806 + modified: 1778327934979 + isPrivate: false + description: "" + sortKey: -1776615518466 + method: GET + body: + mimeType: multipart/form-data + params: + - name: includeOnChainGateways + value: "true" + disabled: false + type: text + - name: includeOffChainGateways + value: "true" + disabled: false + type: text + - name: includeManualGateways + value: "false" + disabled: false + type: text + headers: + - name: Accept-Language + value: FA + - name: Content-Type + value: multipart/form-data + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/DOGE/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4\ + e596e29cc7" + name: Update The Gateway + meta: + id: req_d99a3e07a96e4ff0bfc123696cdc9e8f + created: 1776615524807 + modified: 1776615524807 + isPrivate: false + description: "" + sortKey: -1776615518465 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"type\": \"OffChain\",\r + + \ \"transferMethod\": \"VOUCHER\",\r + + \ \"currencySymbol\": \"USDT\",\r + + \ \"isDepositActive\": true,\r + + \ \"isWithdrawActive\": true,\r + + \ \"withdrawFee\": 0.1,\r + + \ \"withdrawAllowed\": false,\r + + \ \"depositAllowed\": true,\r + + \ \"depositMin\": 1,\r + + \ \"depositMax\": 50,\r + + \ \"withdrawMin\": 2,\r + + \ \"withdrawMax\": 10,\r + + \ \"depositDescription\": null,\r + + \ \"withdrawDescription\": null,\r + + \ \"displayOrder\": 3\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/IRT/gateway/ofg_b2ae229e-3387-4d71-abe9-d82\ + ed8500b02" + name: Delete The Gateway + meta: + id: req_42cf4905486b4bfea2946f9a9e706a80 + created: 1776615524808 + modified: 1776615524808 + isPrivate: false + description: "" + sortKey: -1776615518464 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/gateway/ofg_c471822f-0f22-42e6-ab57-a4dd056\ + 43e6f/terminal" + name: Assign terminal to a gateway + meta: + id: req_d6021dc715b548a68cf5602db667ea78 + created: 1776615524808 + modified: 1776615524808 + isPrivate: false + description: "" + sortKey: -1776615518463 + method: POST + body: + mimeType: application/json + text: '["4c84512d-901e-4575-bd7e-f68e8c66e137"]' + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/gateway/ofg_c471822f-0f22-42e6-ab57-a4dd056\ + 43e6f/terminal" + name: Delete gateway's terminal + meta: + id: req_58870d4a7900404791695ed23e4b340c + created: 1776615524809 + modified: 1776615524809 + isPrivate: false + description: "" + sortKey: -1776615518462 + method: DELETE + body: + mimeType: application/json + text: '["ac4029d1-ed4c-4430-a3ed-788bef525880"]' + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/gateway/ofg_c471822f-0f22-42e6-ab57-a4dd056\ + 43e6f/terminal" + name: Get gateway's terminal + meta: + id: req_74651f24239e4d8f8c5c276626c44b39 + created: 1776615524810 + modified: 1776615524810 + isPrivate: false + description: "" + sortKey: -1776615518461 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/IRT/gateway/ofg_2adf97d0-06c2-4528-9f04-396\ + dcce301be" + name: Update The Gateway - DepositDes + meta: + id: req_c16f3a2baba04ab1b54035f360a3a58c + created: 1776615524811 + modified: 1776615524811 + isPrivate: false + description: "" + sortKey: -1776615518460 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"type\": \"OffChain\",\r + + \ \"depositMin\": 10000,\r + + \ \"depositMax\": 50000000,\r + + \ \"withdrawMin\": 10000,\r + + \ \"withdrawMax\": 50000000,\r + + \ \"isDepositActive\": true,\r + + \ \"isWithdrawActive\": false,\r + + \ \"withdrawFee\": 10000,\r + + \ \"withdrawAllowed\": true,\r + + \ \"depositAllowed\": true,\r + + \ \"transferMethod\": \"SHEBA\",\r + + \ \"displayOrder\": 2,\r + + \ \"depositDescription\": \"پس از انتخاب بانک مقصد و شماره + شبای نمایش‌داده‌شده، مبلغ موردنظر را «فقط از حسابی به نام + خودتان» با روش انتقال وجه از طریق شبا و با ثبت «شناسه واریز» + درج‌شده انتقال دهید.\\n\\n- حساب مبدا حتماً باید به نام + خودتان باشد؛ در غیر این صورت مبلغ واریز شده به حساب مبدا + عودت داده خواهد شد.\\n- در صورت عدم ثبت یا ثبت اشتباه شناسه + واریز، مبلغ به حساب شما نخواهد نشست. پیگیری آن در اوپکس + مقدور نیست و نهایتاً تا ۷۲ ساعت به حساب مبدا + بازمی‌گردد.\",\r + + \ \"withdrawDescription\": null\r + + }\r\n" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/currency/IRT/gateway" + name: Create Onchain Gateway + meta: + id: req_a2fc6437a7c5458daa6f3cdc7160f46b + created: 1778083502093 + modified: 1778345259535 + isPrivate: false + description: "" + sortKey: -1776615518466.5 + method: POST + body: + mimeType: application/json + text: |- + { + "type": "OnChain", + "implementationSymbol":"irt", + "depositMin": 50000, + "depositMax": 10000000, + "withdrawMin": 50000, + "withdrawMax": 10000000, + "isActive": true, + "withdrawFee": 10000, + "withdrawAllowed": true, + "depositAllowed": true, + "isDepositActive": true, + "isWithdrawActive": true, + "decimal":2, + "chain":"btc" + } + headers: + - name: Content-Type + value: application/json + - name: "Authorization " + value: Bearer + eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0TE5KVE44SnJjdmM1Nno3ZklocUVwZnJWUEhFNlJvdDZ5V2VXN3JMNXpBIn0.eyJleHAiOjE3NzgwODYwNDcsImlhdCI6MTc3ODA4NTQ0NywianRpIjoiMDdlY2M5NTAtNTc3ZC00ZmQzLWJhZDctMzZhMWU0Y2UxMmQ2IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJzdWIiOiI5ZjNlOTQ4MC05MWY3LTQ5YjEtOTA1Zi03ZGRkMThhYWMzMDEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiZmFlYjdhNDAtYzNkYi00OTY1LWE5NTctZWVkNzE4ODMzOWJlIiwic2NvcGUiOiJ0cnVzdCIsInBlcm1pc3Npb25zIjpbImRlcG9zaXQ6d3JpdGUiLCJvcmRlcjp3cml0ZSIsImFkZHJlc3M6YXNzaWduIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiIsImRlcG9zaXQ6d3JpdGUiLCJ3aXRoZHJhdzp3cml0ZSIsInZvdWNoZXI6c3VibWl0IiwiYmFua19hY2NvdW50OndyaXRlIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJzdXBlci1hZG1pbiIsImRlZmF1bHQtcm9sZXMtb3BleCIsImFkbWluIiwidXNlci0yIiwidXNlciJdLCJlbWFpbCI6ImFkbWluQG9wZXguZGV2IiwidXNlcm5hbWUiOiJhZG1pbiJ9.Z6tQXcIRJjlTMCeDecSL7WMDGG0gpzsvX9okGrjcTDVT-g26vJI_JaLf-epf-z1mzKHtxj4GvD4NjCQeDwayawF1AEQC1tmr3XFd5ddDzPmBKozG7iWvB5u_-ikX2WZHTn4PsjuUSeZRAjytu5CyCHSJrTvURj2yXpkmXDXIsZZzBTRhx2UAN0cAjNlZ5-r0PwRI4B0sc6sC8kW7fVuFVjtzCwm062DlpSg6IoFY_UUQNhrOeCPObBTuWx7zM_N_7kqRxsFeLqQ-tjkqonMkgUZeT8vcoMzxGGJ4-bLoRazS3rINJglpTudQ2NxZVFBfAiWT2jKODIyvLj8r3ETHDQ + description: "" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{ _['super-admin-token'] }}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: terminal + meta: + id: fld_5f82d453447d4e2fb00528c5b4fdb775 + created: 1776615524811 + modified: 1776615524811 + sortKey: -1776615518459 + description: "" + children: + - url: "{{_['wallet-host']}}/admin/deposit/terminal" + name: Create + meta: + id: req_a202dd777a2b48499451236d81481163 + created: 1776615524813 + modified: 1776615524813 + isPrivate: false + description: "" + sortKey: -1776615518458 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"owner\": \"سامان\",\r + + \ \"identifier\": \" \",\r + + \ \"active\": true,\r + + \ \"type\": \"IPG\", //CARD , SHEBA , IPG , EXCHANGE \r + + \ \"metaData\": \"saman\",\r + + \ \"description\" : \"\" //optional\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/deposit/terminal/4c84512d-901e-4575-bd7e-f68e8\ + c66e137" + name: Update + meta: + id: req_32797b283f9041bab6172787454b7171 + created: 1776615524814 + modified: 1776615524814 + isPrivate: false + description: "" + sortKey: -1776615518457 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"owner\": \"آسان پرداخت\",\r + + \ \"identifier\": \" \",\r + + \ \"active\": true,\r + + \ \"type\": \"IPG\", //CARD , SHEBA , IPG , EXCHANGE \r + + \ \"metaData\": \"sadad\",\r + + \ \"description\" : \"\" //optional\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['base-url-wallet']}}/admin/deposit/terminal/ac4029d1-ed4c-4430-a3ed-7\ + 88bef525880" + name: Delete + meta: + id: req_8e79b54b17d240b0a267545c504e7f1b + created: 1776615524815 + modified: 1776615524815 + isPrivate: false + description: "" + sortKey: -1776615518456 + method: DELETE + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/deposit/terminal" + name: Get + meta: + id: req_c7a9426cab4e4f70941be326a360e889 + created: 1776615524816 + modified: 1776615524816 + isPrivate: false + description: "" + sortKey: -1776615518455 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Voucher + meta: + id: fld_b55ac1270a8b4753b5afe7b694d8a214 + created: 1776615524820 + modified: 1776615524820 + sortKey: -1776615518450 + description: "" + children: + - url: "{{_['wallet-host']}}/admin/voucher/dr-1234567890" + name: Get Voucher Data + meta: + id: req_bff7f68f7c644945a492dfd5c75c624c + created: 1776615524821 + modified: 1776615524821 + isPrivate: false + description: "" + sortKey: -1776615518449 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/admin/voucher" + name: Get Vouchers Data + meta: + id: req_48b94b54818d4968a952fb60bec86a16 + created: 1776615524822 + modified: 1776615524822 + isPrivate: false + description: "" + sortKey: -1776615518448 + method: GET + parameters: + - name: isUsed + value: "true" + disabled: false + - name: type + value: SALE + disabled: false + - name: issuer + value: Nilin + disabled: true + - name: limit + value: "10" + disabled: true + - name: | + offset + value: "0" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/voucher/afce5c6dbcb64c63" + name: Submit Voucher + meta: + id: req_916120fbfca44f29bf63aa0fe17e1051 + created: 1776615524823 + modified: 1776615524823 + isPrivate: false + description: "" + sortKey: -1776615518447 + method: PUT + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: | + {{_['wallet-host']}}/admin/voucher/sell/DST-1025 + name: Get Sell Voucher Data + meta: + id: req_2eda3a5738754a16998b56ab8e211a7c + created: 1776615524824 + modified: 1776615524824 + isPrivate: false + description: "" + sortKey: -1776615518446 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: | + {{_['wallet-host']}}/admin/voucher/sell + name: Sell Voucher + meta: + id: req_2d54b817b22b4c6a86e267fc73229db8 + created: 1776615524825 + modified: 1776615524825 + isPrivate: false + description: "" + sortKey: -1776615518445 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"publicCode\" : \"DST-1000\",\r + + \ \"nationalCode\": \"1234567890\",\r + + \ \"phoneNumber\" : \"09981390909\",\r + + \ \"transactionNumber\" : \"1987654321\",\r + + \ \"transactionAmount\" : \"100000\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: chain + meta: + id: fld_964414e8723e496e8389078db4e30156 + created: 1776615524825 + modified: 1776615524825 + sortKey: -1776615518444 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/market/chain" + name: chains + meta: + id: req_713dd43a20674e11a717ad0f7c2854e2 + created: 1776615524826 + modified: 1776615524826 + isPrivate: false + description: "" + sortKey: -1776615518443 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: otp + meta: + id: fld_4c4fc1fd81124dbebadd00409cf3d218 + created: 1776615524827 + modified: 1776615524827 + sortKey: -1776615518442 + description: "" + children: + - url: http://localhost:8097/v1/otp + name: Request otp + meta: + id: req_4fa7692664ef4550bb08ecd005cfdbf3 + created: 1776615524827 + modified: 1776615524827 + isPrivate: false + description: "" + sortKey: -1776615518441 + method: POST + body: + mimeType: application/json + text: |- + [ + { + "receiver": "09383381451", + "type": "SMS" + }, + { + "receiver": "email@opex.dev", + "type": "EMAIL" + } + ] + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8097/v1/otp/verify/59816858-0544-4e84-9b89-6db2cb4694eb + name: verify otp + meta: + id: req_492d676d54c344a589653a31f4f3fcc5 + created: 1776615524829 + modified: 1776615524829 + isPrivate: false + description: "" + sortKey: -1776615518440 + method: POST + body: + mimeType: application/json + text: |- + [ + { + "code": "796229", + "type": "SMS" + }, + { + "code": "KqpAKxXh", + "type": "EMAIL" + } + ] + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8097/v1/totp/setup + name: Setup totp + meta: + id: req_f08aa5379bb04bc2ac2648e2cda4907c + created: 1776615524830 + modified: 1776615524830 + isPrivate: false + description: "" + sortKey: -1776615518439 + method: POST + body: + mimeType: application/json + text: |- + { + "userId": "1234", + "label": "a@a.c" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8097/v1/totp/setup/verify + name: Verify setup totp + meta: + id: req_e3dd8f815de1428094cee545872b0448 + created: 1776615524831 + modified: 1776615524831 + isPrivate: false + description: "" + sortKey: -1776615518438 + method: POST + body: + mimeType: application/json + text: |- + { + "userId": "1234", + "code": "395491" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8097/v1/totp/verify + name: Verify totp + meta: + id: req_a3b9f6d3a0344049918ff5a50f8ddd76 + created: 1776615524832 + modified: 1776615524832 + isPrivate: false + description: "" + sortKey: -1776615518437 + method: POST + body: + mimeType: application/json + text: |- + { + "userId": "1234", + "code": "940557" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: http://localhost:8097/v1/totp + name: Delete totp + meta: + id: req_0a813b34a95149ce9715706d7690dcf7 + created: 1776615524833 + modified: 1776615524833 + isPrivate: false + description: "" + sortKey: -1776615518436 + method: DELETE + body: + mimeType: application/json + text: |- + { + "userId": "1234", + "code": "124690" + } + headers: + - name: Content-Type + value: application/json + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: New UI Services + meta: + id: fld_75d79988593b49bc824f075a407a664b + created: 1776615524833 + modified: 1776615524833 + sortKey: -1776615518435 + description: "" + children: + - url: "" + name: Get users detail assets + meta: + id: req_aea3f8a952ba4724bc6ed909475b6d8c + created: 1776615524885 + modified: 1776615524885 + isPrivate: false + description: "" + sortKey: -1776615518382 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: History and Summary + meta: + id: fld_6e851fbe4b5b4d11a1dab8b07d24de6b + created: 1776615524834 + modified: 1776615524834 + sortKey: -1776615518434 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/user/history/order/count" + name: Get user order history count + meta: + id: req_1bc4934d616e4a13b99cb5577d4cdb36 + created: 1776615524835 + modified: 1776615524835 + isPrivate: false + description: "" + sortKey: -1776615518432 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: true + - name: orderType + value: LIMIT_ORDER + disabled: true + - name: direction + value: ASK + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/order" + name: Get user order history + meta: + id: req_2513c1b73b4c414a87fa322ba0ed10a8 + created: 1776615524835 + modified: 1776615524835 + isPrivate: false + description: "" + sortKey: -1776615518433 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: true + - name: orderType + value: LIMIT_ORDER + disabled: true + - name: direction + value: ASK + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + - name: limit + value: "1" + disabled: true + - name: offset + value: "0" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/trade" + name: Get user trade history + meta: + id: req_9151e46c1926430a8887e8db93db5739 + created: 1776615524837 + modified: 1776615524837 + isPrivate: false + description: "" + sortKey: -1776615518431 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: true + - name: direction + value: ASK + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + - name: limit + value: "1" + disabled: true + - name: offset + value: "0" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/trade/count" + name: Get user trade history count + meta: + id: req_5eb30e919f344ec9a66230256efa72e7 + created: 1776615524838 + modified: 1776615524838 + isPrivate: false + description: "" + sortKey: -1776615518430 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: true + - name: direction + value: ASK + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/withdraw" + name: Get user withdraw history + meta: + id: req_f977a6d8c10c4debb7ace25826a0a549 + created: 1776615524838 + modified: 1776615524838 + isPrivate: false + description: "" + sortKey: -1776615518429 + method: GET + parameters: + - name: currency + value: BTC + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + - name: limit + value: "1" + disabled: true + - name: offset + value: "0" + disabled: true + - name: ascendingByTime + value: "true" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/withdraw/count" + name: Get user withdraw history count + meta: + id: req_9f349c8641644c25aacd431e0a1dd126 + created: 1776615524839 + modified: 1776615524839 + isPrivate: false + description: "" + sortKey: -1776615518428 + method: GET + parameters: + - name: currency + value: BTC_USDT + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/summary/trade" + name: Get user trade summary + meta: + id: req_9d8cb3667d5547d6b1286d37ba22e1ac + created: 1776615524840 + modified: 1776615524840 + isPrivate: false + description: "" + sortKey: -1776615518427 + method: GET + parameters: + - name: limit + value: "10" + disabled: false + - name: startTime + value: "1" + disabled: false + - name: endTime + value: "1745267400000" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/summary/deposit" + name: Get user deposit summary + meta: + id: req_1cb8a878914647bba06f8926d2856a2a + created: 1776615524841 + modified: 1776615524841 + isPrivate: false + description: "" + sortKey: -1776615518426 + method: GET + parameters: + - name: limit + value: "10" + disabled: false + - name: startTime + value: "1745181000000" + disabled: false + - name: endTime + value: "1745267400000" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/summary/withdraw" + name: Get user withdraw summary + meta: + id: req_db76f5b96b974d8f8ef04a81803f18f9 + created: 1776615524842 + modified: 1776615524842 + isPrivate: false + description: "" + sortKey: -1776615518425 + method: GET + parameters: + - name: limit + value: "10" + disabled: false + - name: startTime + value: "1" + disabled: false + - name: endTime + value: "1745267400000" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/deposit/count" + name: Get user deposit history count + meta: + id: req_88dd5d44c0104defb80c57f35c132fdd + created: 1776615524843 + modified: 1776615524843 + isPrivate: false + description: "" + sortKey: -1776615518423 + method: GET + parameters: + - name: currency + value: BTC_USDT + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/deposit" + name: Get user deposit history + meta: + id: req_a47aa34e0d6f4b5f9f40dcc929411de9 + created: 1776615524843 + modified: 1776615524843 + isPrivate: false + description: "" + sortKey: -1776615518424 + method: GET + parameters: + - name: currency + value: BTC + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + - name: limit + value: "1" + disabled: true + - name: offset + value: "0" + disabled: true + - name: ascendingByTime + value: "true" + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/transaction" + name: Get user transaction history + meta: + id: req_8a81a6e5d5c0427c8d3d7390eb3b81df + created: 1776615524845 + modified: 1776615524845 + isPrivate: false + description: "" + sortKey: -1776615518422 + method: GET + parameters: + - name: currency + value: BTC + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + - name: limit + value: "1" + disabled: true + - name: offset + value: "0" + disabled: true + - name: ascendingByTime + value: "true" + disabled: true + - name: category + value: TRADE + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/transaction/count" + name: Get user transaction history count + meta: + id: req_b8b9166dc5f745e7b33e35772ba1710a + created: 1776615524846 + modified: 1776615524846 + isPrivate: false + description: "" + sortKey: -1776615518421 + method: GET + parameters: + - name: currency + value: BTC_USDT + disabled: true + - name: startTime + value: "1716437636490" + disabled: true + - name: endTime + value: "1746437636490" + disabled: true + - name: category + value: TRADE + disabled: true + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/swap" + name: Get user swap history + meta: + id: req_d527d8b11e9b4475ad6805ef81e5ea3f + created: 1776615524847 + modified: 1776615524847 + isPrivate: false + description: "" + sortKey: -1776615518420 + method: POST + body: + mimeType: application/json + text: "{\r + + \ // sourceSymbol\r + + \ // destSymbol\r + + \ // startTime\r + + \ // endTime\r + + \ // limit (default 10)\r + + \ // offset (default 0)\r + + \ // ascendingByTime (default false)\r + + \r + + \ // ** All Optional **\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/history/swap/count" + name: Get user swap history count + meta: + id: req_52938c4c01454d9194f429fa13721c5e + created: 1776615524848 + modified: 1776615524848 + isPrivate: false + description: "" + sortKey: -1776615518419 + method: POST + body: + mimeType: application/json + text: "{\r + + \ // sourceSymbol\r + + \ // destSymbol\r + + \ // startTime\r + + \ // endTime\r + + \r + + \ // ** All Optional **\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Wallet + meta: + id: fld_1bb957d952a8427baa3f17cab05b8e6e + created: 1776615524849 + modified: 1776615524849 + sortKey: -1776615518418 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/wallet/asset" + name: Get User Wallet Asset + meta: + id: req_cfdc366084ed45818cf641d2c87b76b7 + created: 1776615524857 + modified: 1776615524857 + isPrivate: false + description: "" + sortKey: -1776615518409 + method: GET + parameters: + - name: symbol + value: BTC + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Withdraw + meta: + id: fld_9357a5de127344c2be8f0b3229bb4abf + created: 1776615524849 + modified: 1776615524849 + sortKey: -1776615518417 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/withdraw" + name: Request withdraw + meta: + id: req_a71a73e511a34bb0bacad1b167084e3a + created: 1776615524850 + modified: 1776615524850 + isPrivate: false + description: "" + sortKey: -1776615518416 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"currency\": \"IRT\",\r + + \ \"amount\": 100,\r + + // \"destSymbol\": \"USDT\",\r + + \ \"destAddress\": + \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r + + // \"destNetwork\": \"test-ethereum\",\r + + \ \"destNote\": \"Personal wallet\", //Optional\r + + \ \"description\": \"Withdrawal to personal wallet\" + ,//Optional\r + + \ + \"gatewayUuid\":\"ofg_0843c1f0-a35d-4ead-a427-9c262924f\ + 9f7\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/withdraw/5/cancel" + name: Cancel withdraw + meta: + id: req_0a78f954fc464ec99c7bc784376e6bbc + created: 1776615524851 + modified: 1776615524851 + isPrivate: false + description: "" + sortKey: -1776615518415 + method: PUT + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/withdraw/5" + name: Get withdraw + meta: + id: req_f4d005d7419b4069aca18a24e357b86c + created: 1776615524852 + modified: 1776615524852 + isPrivate: false + description: "" + sortKey: -1776615518414 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/withdraw/78/otp/EMAIL/request" + name: Request OTP + meta: + id: req_a9f03524774e4a5d8b33c6ec918298f6 + created: 1776615524853 + modified: 1776615524853 + isPrivate: false + description: "" + sortKey: -1776615518413 + method: POST + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/withdraw/78/otp/EMAIL/verify" + name: Verify OTP + meta: + id: req_01c7fb7c94b449f6bd40231f12b30919 + created: 1776615524854 + modified: 1776615524854 + isPrivate: false + description: "" + sortKey: -1776615518412 + method: POST + parameters: + - name: otpCode + value: a123d22 + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Deposit + meta: + id: fld_7a0b380889164252aebc08de86a43da0 + created: 1776615524855 + modified: 1776615524855 + sortKey: -1776615518411 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/deposit" + name: Deposit + meta: + id: req_2b063833a5504a4490437a7da60803d1 + created: 1776615524856 + modified: 1776615524856 + isPrivate: false + description: "" + sortKey: -1776615518410 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"symbol\" :\"BTC\",\r + + \ \"receiverUuid\" :\"1\",\r + + \ \"receiverWalletType\" :\"MAIN\",\r + + \ \"amount\" :123,\r + + \ \"description\" : \"\",\r + + \ \"transferRef\" : \"\",\r + + \ \"gatewayUuid\" : \"\",\r + + \ \"chain\" : \"\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Exchange info + meta: + id: fld_cf0bf387d3e4412681b24ffc82190aa8 + created: 1776615524857 + modified: 1776615524857 + sortKey: -1776615518408 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/market/fee" + name: Get fee levels + meta: + id: req_41d18e51c0d44a58b3c989a2838d6c09 + created: 1776615524858 + modified: 1776615524858 + isPrivate: false + description: "" + sortKey: -1776615518407 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/pair" + name: Get pair info + meta: + id: req_58b5d353da2b4e03a982e87410435d7f + created: 1776615524859 + modified: 1776615524859 + isPrivate: false + description: "" + sortKey: -1776615518406 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/currency" + name: Get currency + meta: + id: req_1a9d36ef7afa4d6a8763383d6a652904 + created: 1776615524860 + modified: 1776615524860 + isPrivate: false + description: "" + sortKey: -1776615518405 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/currency/gateway" + name: Get gateway + meta: + id: req_b0aa36bdb6b84d2789866e30450851e7 + created: 1776615524861 + modified: 1776615524861 + isPrivate: false + description: "" + sortKey: -1776615518404 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/stats" + name: Get market stats + meta: + id: req_9e9793903fcf4fc68fc9bab623a23f4e + created: 1776615524862 + modified: 1776615524862 + isPrivate: false + description: "" + sortKey: -1776615518403 + method: GET + parameters: + - name: interval + value: 7d + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/info" + name: Get market info + meta: + id: req_ed4f0fa65c1d4edeafa3db82a11fdfd9 + created: 1776615524863 + modified: 1776615524863 + isPrivate: false + description: "" + sortKey: -1776615518402 + method: GET + parameters: + - name: interval + value: 1Y + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/ticker/1M" + name: Get price change + meta: + id: req_ae511914d0ab44f5a747e59ee9446f63 + created: 1776615524864 + modified: 1776615524864 + isPrivate: false + description: "" + sortKey: -1776615518401 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/ticker/price" + name: Get price ticker + meta: + id: req_585149b3dfd84327b96c8835e9102716 + created: 1776615524865 + modified: 1776615524865 + isPrivate: false + description: "" + sortKey: -1776615518400 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/currencyInfo/quotes" + name: Get quote currencies + meta: + id: req_672e7c4bfe93415684836c4856be6b6a + created: 1776615524865 + modified: 1776615524865 + isPrivate: false + description: "" + sortKey: -1776615518399 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/klines" + name: Get klines + meta: + id: req_520475cb798840a783d4beb0c7f2af7b + created: 1776615524866 + modified: 1776615524866 + isPrivate: false + description: "" + sortKey: -1776615518398 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: false + - name: interval + value: 1M + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/basic-data" + name: Get basic data + meta: + id: req_d9411af2df4844a79da8219653aebd0f + created: 1776615524867 + modified: 1776615524867 + isPrivate: false + description: "" + sortKey: -1776615518397 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/market/withdraw-limits" + name: Get withdraw limits + meta: + id: req_325500825f1a4b90bdeb99af272a7418 + created: 1776615524868 + modified: 1776615524868 + isPrivate: false + description: "" + sortKey: -1776615518396 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Order + meta: + id: fld_7201162a1e0949de83acb1a7b8904670 + created: 1776615524869 + modified: 1776615524869 + sortKey: -1776615518395 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/market/depth" + name: Get order book + meta: + id: req_500f9bba8eb54f2a9c652d288f672fdc + created: 1776615524870 + modified: 1776615524870 + isPrivate: false + description: "" + sortKey: -1776615518394 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/order" + name: Create order + meta: + id: req_f325022865d947348ec26b218fb01b92 + created: 1776615524871 + modified: 1776615524871 + isPrivate: false + description: "" + sortKey: -1776615518393 + method: POST + parameters: + - name: symbol + value: BTC_USDT + disabled: false + - name: side + value: SELL + disabled: false + - name: type + value: LIMIT + disabled: false + - name: timeInForce + value: GTC + disabled: false + - name: timestamp + value: "1626805452" + disabled: false + - name: quantity + value: "0.1" + disabled: false + - name: price + value: "100500" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/order" + name: Get order + meta: + id: req_a7e777b3b45b442982a0c43df50c9628 + created: 1776615524872 + modified: 1776615524872 + isPrivate: false + description: "" + sortKey: -1776615518392 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: false + - name: orderId + value: "37" + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/order" + name: Cancel order + meta: + id: req_0b2e2da258434d00bf552eccb7e6f6c5 + created: 1776615524873 + modified: 1776615524873 + isPrivate: false + description: "" + sortKey: -1776615518391 + method: PUT + parameters: + - name: symbol + value: BTC_USDT + disabled: false + - name: orderId + value: "37" + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/order/open" + name: Get Open Orders + meta: + id: req_9001ec86cb81425da7070d4f5b0bcb87 + created: 1776615524874 + modified: 1776615524874 + isPrivate: false + description: "" + sortKey: -1776615518390 + method: GET + parameters: + - name: symbol + value: BTC_USDT + disabled: false + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Voucher + meta: + id: fld_6590767246ea4d828edb032c1f7e8ce4 + created: 1776615524875 + modified: 1776615524875 + sortKey: -1776615518389 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/voucher/CJB51X" + name: Submit voucher + meta: + id: req_b5c0b8c4a7204b64b1a4651054cd4a01 + created: 1776615524875 + modified: 1776615524875 + isPrivate: false + description: "" + sortKey: -1776615518388 + method: PUT + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: User + meta: + id: fld_d1812777d63c4970b31f17a3bfaad8e6 + created: 1776615524877 + modified: 1776615524877 + sortKey: -1776615518387 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/user/data/trade/volume/total" + name: Get total trade volume value + meta: + id: req_d2719cafb1a645e583333a2625daa414 + created: 1776615524878 + modified: 1776615524878 + isPrivate: false + description: "" + sortKey: -1776615518386 + method: GET + parameters: + - name: interval + value: Month + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/data/trade/volume" + name: Get total trade volume by symbol + meta: + id: req_aae9309e73db4e79888755e54e90776b + created: 1776615524880 + modified: 1776615524880 + isPrivate: false + description: "" + sortKey: -1776615518385 + method: GET + parameters: + - name: interval + value: Day + disabled: false + - name: symbol + value: BTC + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/data/fee" + name: Get user fee level + meta: + id: req_1eec675a660843a590c7f6b0795226b4 + created: 1776615524882 + modified: 1776615524882 + isPrivate: false + description: "" + sortKey: -1776615518384 + method: GET + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['api-host']}}/opex/v1/user/data/withdraw/volume/total" + name: Get User withdraw volume + meta: + id: req_3ddaa7d90a6447629c29e75992f667e5 + created: 1776615524882 + modified: 1776615524882 + isPrivate: false + description: "" + sortKey: -1776615518383 + method: GET + parameters: + - name: interval + value: 1w + disabled: true + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Messages + meta: + id: fld_2c774d8e716546e9b34751d568eb9be1 + created: 1776615524886 + modified: 1776615524886 + sortKey: -1776615518381 + description: "" + children: + - url: "{{host}}/config/messages" + name: Search for messages + meta: + id: req_a24c6fdb68be450798ada93177d82a4e + created: 1776615524887 + modified: 1776615524887 + isPrivate: false + description: "" + sortKey: -1776615518380 + method: GET + parameters: + - name: key + value: tg + disabled: true + - name: message + value: tg + disabled: true + - name: category + value: "" + disabled: true + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{host}}/config/messages" + name: Create or update a message + meta: + id: req_ab1cdc90b6c94ed08f31bcb7ac53ec9c + created: 1776615524888 + modified: 1776615524888 + isPrivate: false + description: "" + sortKey: -1776615518379 + method: POST + body: + mimeType: application/json + text: "{\r + + \ \"key\": \"USDT\",\r + + \ \"userLanguage\": \"EN\",\r + + \ \"message\": \"TETHERRR\",\r + + \ \"category\":\"ERROR_CODE\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{host}}/config/messages" + name: Delete + meta: + id: req_1099e3e64865453cb9ca2f16280f9602 + created: 1776615524889 + modified: 1776615524889 + isPrivate: false + description: "" + sortKey: -1776615518378 + method: DELETE + body: + mimeType: application/json + text: "{\r + + \ \"key\": \"USDT\",\r + + \ \"userLanguage\": \"EN\",\r + + \ \"category\": \"ERROR_CODE\"\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Otc + meta: + id: fld_305d29001c834414b88e6abd5450c9d9 + created: 1776615524890 + modified: 1776615524890 + sortKey: -1776615518377 + description: "" + children: + - url: "{{_['wallet-host']}}/otc/route" + name: Get route + meta: + id: req_2f606fd85e9348e4ae42f9f2c34e5393 + created: 1776615524891 + modified: 1776615524891 + isPrivate: false + description: "" + sortKey: -1776615518376 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/otc/rate" + name: Get rate + meta: + id: req_8b2314eb77f548f192ba9b7f638e9264 + created: 1776615524891 + modified: 1776615524891 + isPrivate: false + description: "" + sortKey: -1776615518375 + method: GET + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/otc/rate" + name: Add rate + meta: + id: req_355fb2d91e2f48538539b62950ad86a8 + created: 1776615524892 + modified: 1776615524892 + isPrivate: false + description: "" + sortKey: -1776615518374 + method: POST + body: + mimeType: application/json + text: |- + { + "sourceSymbol": "BNB", + "destSymbol": "IRT", + "rate": 53208905.1092900039676578671 + } + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/otc/rate" + name: Update rate + meta: + id: req_5c58c7a7bcd24390aa03bc02850983cc + created: 1776615524894 + modified: 1776615524894 + isPrivate: false + description: "" + sortKey: -1776615518372 + method: PUT + body: + mimeType: application/json + text: "{\r + + \ \"sourceSymbol\": \"USDT\",\r + + \ \"destSymbol\": \"IRT\",\r + + \ \"rate\": 98.25\r + + }" + headers: + - name: Content-Type + value: application/json + authentication: + type: bearer + disabled: false + token: "{{_['super-admin-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: "{{_['wallet-host']}}/otc/currency/price" + name: Get currency price + meta: + id: req_a918a366b7d448e1876fcaa2f9d9b70e + created: 1776615524894 + modified: 1776615524894 + isPrivate: false + description: "" + sortKey: -1776615518373 + method: GET + body: + mimeType: application/x-www-form-urlencoded + params: + - name: unit + value: USDT + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: bc-gateway + meta: + id: fld_806840601011492694d079ca19d0726f + created: 1776615524896 + modified: 1776615524896 + sortKey: -1776615518371 + description: "" + children: + - url: "{{_['api-host']}}/opex/v1/wallet/deposit/address" + name: assign + meta: + id: req_545b44b7943747659ad7508d5dd92724 + created: 1776615524897 + modified: 1776615524897 + isPrivate: false + description: "" + sortKey: -1776615518370 + method: GET + parameters: + - name: currency + value: BTC + disabled: false + - name: gatewayUuid + value: ong_abff8165-7e15-424f-b6f9-3e6e80941741 + disabled: false + authentication: + type: bearer + disabled: false + token: "{{_['user-token']}}" + prefix: "" + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - name: Kavenegar + meta: + id: fld_793d07a5e44d4567b1d8d41ae953c0c2 + created: 1776615524898 + modified: 1776615524898 + sortKey: -1776615518369 + description: "" + children: + - url: | + https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json + name: | + https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json + meta: + id: req_68cdb622a451476c80bf1cea5806d549 + created: 1776615524898 + modified: 1776615524898 + isPrivate: false + description: "" + sortKey: -1776615518368 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: receptor + value: "09336461763" + disabled: false + - name: sender + value: "90002350" + disabled: false + - name: message + value: |- + Code: 940852 + Dorost + دُرست + کد اعتبارسنجی: 940852 + + @beta.dorost.com #940852 + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true + - url: | + https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json + name: |- + https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json + Copy + meta: + id: req_e76ade0a0638459e90d512fb5955fd81 + created: 1776615524899 + modified: 1776615524899 + isPrivate: false + description: "" + sortKey: -1776615518367 + method: POST + body: + mimeType: application/x-www-form-urlencoded + params: + - name: receptor + value: "09336461763" + disabled: false + - name: sender + value: "90002350" + disabled: false + - name: message + value: |- + Code: 940852 + Dorost + دُرست + کد اعتبارسنجی: 940852 + + @beta.dorost.com #940852 + disabled: false + headers: + - name: Content-Type + value: application/x-www-form-urlencoded + settings: + renderRequestBody: true + encodeUrl: true + followRedirects: global + cookies: + send: true + store: true + rebuildPath: true +cookieJar: + name: Default Jar + meta: + id: jar_f655ac09bdcefb9a402de78c571d5da38c23e416 + created: 1776614688094 + modified: 1776614688094 +environments: + name: Base Environment + meta: + id: env_f655ac09bdcefb9a402de78c571d5da38c23e416 + created: 1776614688092 + modified: 1776683924062 + isPrivate: false + subEnvironments: + - name: EXKY-PRD + meta: + id: env_21d5b741eb3845048f437b85ebe95cb7 + created: 1776682961306 + modified: 1776683571659 + isPrivate: false + sortKey: 1776682961306 + data: + host: https://api.exky.io + api-host: https://api.exky.io/api + auth-host: https://api.exky.io + wallet-host: https://api.exky.io/wallet + admin-host: https://api.exky.io/admin + config-host: https://api.exky.io/config + user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiWGwtUks3NnFhU1N5NTYxaU5wS19XX0NpN3VMQWRaMHhQUzJLaTJKc2NBIn0.eyJleHAiOjE3MjIwODcwMzQsImlhdCI6MTcyMjA4MzQzNCwianRpIjoiYTFhYzkzYjgtODMyYy00YWMyLWFjY2MtZWZhYmE1NjdkYWMyIiwiaXNzIjoiaHR0cHM6Ly9hcGkuZXhreS5pby9hdXRoL3JlYWxtcy9vcGV4Iiwic3ViIjoiZGJmN2Q5NmUtMjM4ZC00ODk0LThiOTEtMGI1ODBkY2IxMTk4IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNlc3Npb25fc3RhdGUiOiJkMzY0ZmU0ZS05M2ZhLTRjOTgtYmZmNi02YzhmMzVkNTNhYjciLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdfSwic2NvcGUiOiJ0cnVzdCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdLCJuYW1lIjoiQWRtaW4gRmluYW5jZSIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluLmZpbmFuY2VAZXhreS5pbyIsImdpdmVuX25hbWUiOiJBZG1pbiIsImZhbWlseV9uYW1lIjoiRmluYW5jZSIsImVtYWlsIjoiYWRtaW4uZmluYW5jZUBleGt5LmlvIn0.CNB1VEqYjcPSNaQM0CE35sTdeMlf2929aH8d2S9C1M-QYqJIIQFwb2T8Dnh2E8GosFr6Cstmr4JkIDOYVIJ6oqDxRNrB_kNa-ZolvAvuAWQSp38BCjC2zvc7un-CNirz5beQCmP3lboGBhbPqlGPfJjZDO-Eojq863eqGivc87iw7NAejUuMcMBmZ2W373V5xRsk0OxA9zu5ldhHSPrm93jheLjTb01Abwv31khAfqyoZ1kY1QiO3XTYGLtF3KQ3vuo0NgcuByCDZvWrhwzaYYMAWkqWVjY1w8bCw2seKNJoEkHVRYoJDQ0uZcVGWXzYG4GF-ITQGmLlKlN_JrAn4w + web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e + test-user-username: bot1 + test-user-password: 4TGx9sEV25jeCtSA + test-user-email: bot1@exky.io + admin-username: admin.finance@exky.io + admin-password: zm+>DcAF$,eK8:*(&_WaZ^ + super-admin-username: admin@exky.io + super-admin-password: 5M$Q?e7^eFq! + super-admin-token: "" + - name: Opex New + meta: + id: env_e0dac34ffaf7407c8170dfdff24d9dab + created: 1776682965594 + modified: 1776683716433 + isPrivate: false + sortKey: 1776682965594 + data: + host: https://api.exky.io + api-host: https://api.exky.io/api + admin-host: https://api.exky.io/admin + config-host: https://api.exky.io/config + user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiWGwtUks3NnFhU1N5NTYxaU5wS19XX0NpN3VMQWRaMHhQUzJLaTJKc2NBIn0.eyJleHAiOjE3MjIwODcwMzQsImlhdCI6MTcyMjA4MzQzNCwianRpIjoiYTFhYzkzYjgtODMyYy00YWMyLWFjY2MtZWZhYmE1NjdkYWMyIiwiaXNzIjoiaHR0cHM6Ly9hcGkuZXhreS5pby9hdXRoL3JlYWxtcy9vcGV4Iiwic3ViIjoiZGJmN2Q5NmUtMjM4ZC00ODk0LThiOTEtMGI1ODBkY2IxMTk4IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNlc3Npb25fc3RhdGUiOiJkMzY0ZmU0ZS05M2ZhLTRjOTgtYmZmNi02YzhmMzVkNTNhYjciLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdfSwic2NvcGUiOiJ0cnVzdCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdLCJuYW1lIjoiQWRtaW4gRmluYW5jZSIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluLmZpbmFuY2VAZXhreS5pbyIsImdpdmVuX25hbWUiOiJBZG1pbiIsImZhbWlseV9uYW1lIjoiRmluYW5jZSIsImVtYWlsIjoiYWRtaW4uZmluYW5jZUBleGt5LmlvIn0.CNB1VEqYjcPSNaQM0CE35sTdeMlf2929aH8d2S9C1M-QYqJIIQFwb2T8Dnh2E8GosFr6Cstmr4JkIDOYVIJ6oqDxRNrB_kNa-ZolvAvuAWQSp38BCjC2zvc7un-CNirz5beQCmP3lboGBhbPqlGPfJjZDO-Eojq863eqGivc87iw7NAejUuMcMBmZ2W373V5xRsk0OxA9zu5ldhHSPrm93jheLjTb01Abwv31khAfqyoZ1kY1QiO3XTYGLtF3KQ3vuo0NgcuByCDZvWrhwzaYYMAWkqWVjY1w8bCw2seKNJoEkHVRYoJDQ0uZcVGWXzYG4GF-ITQGmLlKlN_JrAn4w + web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e + test-user-username: bot1 + test-user-password: 4TGx9sEV25jeCtSA + test-user-email: bot1@exky.io + admin-username: admin.finance@exky.io + admin-password: zm+>DcAF$,eK8:*(&_WaZ^ + super-admin-username: admin@exky.io + super-admin-password: 5M$Q?e7^eFq! + super-admin-token: "" + - name: Opex Local + meta: + id: env_d89013a70ca04b6db11f00d8ae25c5ba + created: 1776683748193 + modified: 1778404577391 + isPrivate: false + sortKey: 1776683748193 + data: + host: http://localhost:8094 + api-host: http://localhost:8094 + auth-host: http://localhost:8083 + wallet-host: http://localhost:8091 + admin-host: http://localhost:8098 + config-host: http://localhost:9088 + user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiRzQ1UmozQ2dqS0VmT2Y0X2pCekVmck1JdFVSX1Y1a180aGtfckVlcmVNIn0.eyJleHAiOjE3NTQzMTgwNDksImlhdCI6MTc1MzcxMzI0OSwianRpIjoiYjUzNTIyNjYtODhmZS00YzM4LTgzYmItZWQ1NDQ1MGEyYTIwIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsib3BleC1hcGkta2V5IiwiYWNjb3VudCJdLCJzdWIiOiJkNTFiZDc1Yy01YWI2LTQ4ZDEtOGMwNy04MjcyMjljZDM5N2UiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiZDI0YjBkMWYtMzFhZC00ODQ5LTkzMmEtOTRmNmM0NzBkMjczIiwic2NvcGUiOiJ0cnVzdCIsInBlcm1pc3Npb25zIjpbImRlcG9zaXQ6d3JpdGUiLCJvcmRlcjp3cml0ZSIsImFkZHJlc3M6YXNzaWduIl0sInJvbGVzIjpbInVzZXItMSIsImRlZmF1bHQtcm9sZXMtb3BleCIsInVzZXIiXSwiZW1haWwiOiJoaUBvcGV4LmRldiIsInVzZXJuYW1lIjoiaGlAb3BleC5kZXYifQ.l5X2MyJ7UgAqwdY0txW-kjmdThaTNwDGLqqbfp9I46JY_G_1TrPl5PcJNRPM4TsB4IexI8vgJc6zk6Mqo7H3EGx1cpCTvaYLG576SlP3MUd_9p9T3ogzZ0BIQ8cO7IpUqqnzfCiTZODAnXg6fF3vN57TfbDrjR7rzjUigIYRJBUKTVyUeY-S9buAXyyJapqmOJ-7mSJ0nxdOSxAR_KGEXiDCb7jJ1S4UnwNi0UKZvm781wCGN4s_kr-dZCTGYE9x1TOUHYCfwF3It1DCupmUUUm1R_Bljpizndz3wPJzCucWsc-F3QedXJdx-LVbRBTDF_3d + client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjaWwwNVZPYzlORjl6Rm9LMlVOYllEcHdlaWk2bFJQTmZ2NmZKdXJhVWZjIn0.eyJleHAiOjE3NzgzNDg0NzAsImlhdCI6MTc3ODM0NDg3MCwianRpIjoiYTQ3NjcwZTktODc2Ny00OWViLWEzMGEtNGI3NzllZmZmZTMxIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsid2ViLWFwcCIsImFjY291bnQiXSwic3ViIjoiOGI4N2IzMDUtMGNmOC00NWJiLTlmZmItMDZiMDc2YWJmYzlmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNpZCI6IjVjNDJjMmVmLThiNGEtNGViOC1iZTM1LWMzODM3NTI3MmY1NiIsInNjb3BlIjoidHJ1c3QiLCJwZXJtaXNzaW9ucyI6WyJkZXBvc2l0OndyaXRlIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iLCJkZXBvc2l0OndyaXRlIiwid2l0aGRyYXc6d3JpdGUiLCJ2b3VjaGVyOnN1Ym1pdCIsImJhbmtfYWNjb3VudDp3cml0ZSIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iXSwicm9sZXMiOlsidXNlci0xIiwiZGVmYXVsdC1yb2xlcy1vcGV4IiwiYWRtaW4iLCJ1c2VyLTIiLCJ1c2VyIl0sImVtYWlsIjoiYWRtaW5Ab3BleC5kZXYiLCJ1c2VybmFtZSI6ImFkbWluIn0.mNMxjk4TDjz0UuQm5-Sw43ed1Ug-7qJfq_2T2fsGagaWoKDoIByC9sbwb7x6lOszd7HQMqNZYZfDkTQWqMLoEBnoa4UtvNarGz69gZi9n0MDTyxXPmRsL_FB_fSqnN-VompXwW8fPa0S90H2bgP1O7_rkZdIMGMBCLRyyNbct2ln4IdlzSepQ532MWB4UrNT8Rs9rheixpa-1PW1mqhoOhwPXz5zLlA7xNoKho_eo9SfJzmlpiOnwugHmQBXG5O9TlycDCBtDLeLO-RuCTM25oyJR0DWqJT7VEfQ979nXyBqDoNiROMcs8UqoE5cx3HXg92xZ4KnrK3UPiKrLQYzdw + super-admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjaWwwNVZPYzlORjl6Rm9LMlVOYllEcHdlaWk2bFJQTmZ2NmZKdXJhVWZjIn0.eyJleHAiOjE3NzgzNDg0NzAsImlhdCI6MTc3ODM0NDg3MCwianRpIjoiYTQ3NjcwZTktODc2Ny00OWViLWEzMGEtNGI3NzllZmZmZTMxIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsid2ViLWFwcCIsImFjY291bnQiXSwic3ViIjoiOGI4N2IzMDUtMGNmOC00NWJiLTlmZmItMDZiMDc2YWJmYzlmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNpZCI6IjVjNDJjMmVmLThiNGEtNGViOC1iZTM1LWMzODM3NTI3MmY1NiIsInNjb3BlIjoidHJ1c3QiLCJwZXJtaXNzaW9ucyI6WyJkZXBvc2l0OndyaXRlIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iLCJkZXBvc2l0OndyaXRlIiwid2l0aGRyYXc6d3JpdGUiLCJ2b3VjaGVyOnN1Ym1pdCIsImJhbmtfYWNjb3VudDp3cml0ZSIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iXSwicm9sZXMiOlsidXNlci0xIiwiZGVmYXVsdC1yb2xlcy1vcGV4IiwiYWRtaW4iLCJ1c2VyLTIiLCJ1c2VyIl0sImVtYWlsIjoiYWRtaW5Ab3BleC5kZXYiLCJ1c2VybmFtZSI6ImFkbWluIn0.mNMxjk4TDjz0UuQm5-Sw43ed1Ug-7qJfq_2T2fsGagaWoKDoIByC9sbwb7x6lOszd7HQMqNZYZfDkTQWqMLoEBnoa4UtvNarGz69gZi9n0MDTyxXPmRsL_FB_fSqnN-VompXwW8fPa0S90H2bgP1O7_rkZdIMGMBCLRyyNbct2ln4IdlzSepQ532MWB4UrNT8Rs9rheixpa-1PW1mqhoOhwPXz5zLlA7xNoKho_eo9SfJzmlpiOnwugHmQBXG5O9TlycDCBtDLeLO-RuCTM25oyJR0DWqJT7VEfQ979nXyBqDoNiROMcs8UqoE5cx3HXg92xZ4KnrK3UPiKrLQYzdw + test-user-username: test@opex.dev + test-user-password: "12345678" + test-user-email: test@opex.dev + admin-username: admin@gmail.com + admin-password: "12345678" + user-token-2: "" + v2auth-host: http://localhost:8184 + api-key: sdsd + secret: sdfsdf + profile-host: "" + device-host: "" + super-admin-username: "" + super-admin-password: "" + acc-host: "" + bc-gateway-host: http://localhost:8095 + "": "" + - name: Opex Dev + meta: + id: env_e079e933f735438b87e203e51394b838 + created: 1776683906503 + modified: 1776683957963 + isPrivate: false + sortKey: 1776683906503 + data: + host: https://api.opex.dev + api-host: https://api.opex.dev/api + auth-host: https://api.opex.dev + wallet-host: https://api.opex.dev/wallet + admin-host: https://api.opex.dev/admin + config-host: https://api.opex.dev/config + user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NTcxNzI1OTMsImlhdCI6MTc1NzE2ODk5MywianRpIjoiYTNjYjJjYWEtMmI1My00YTg1LWI1NDYtM2IyMzBkMDVhNjcxIiwiaXNzIjoiaHR0cDovL2tjLm9wZXguZGV2OjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJvcGV4LWFwaS1rZXkiLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiODdkZjFmMGYtNjhmNy00ZjA4LTgzMjktZjI5MzAxNDEzZTZkIiwic2NvcGUiOiJ0cnVzdCIsImZpcnN0TmFtZSI6Imtvb3Jvc2giLCJsYXN0TmFtZSI6ImF6aW1pIiwicGVybWlzc2lvbnMiOlsiYWxsIiwiZGVwb3NpdDp3cml0ZSJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJzdXBlci1hZG1pbiIsImRlZmF1bHQtcm9sZXMtb3BleCIsImFkbWluIiwidXNlciJdLCJlbWFpbCI6ImF6aW1pQG9wZXguY29tIiwidXNlcm5hbWUiOiJhemltaSJ9.Cy1gtf1YgRlsvA3YK4oVUdQAzOhkom298M5BMGtcKYkddGzzfq69TiIbh3T0jr915NOCEFW0NR38GiWHcA7W1FtRbKDGFNiGSucLBaL0vkmtz0u5L2GWuSQhYVGulFnqka0yCw8tRjWGhsSU3AVghEMwnCwgeeD3Usx9DHp-m-gQ4VJvmHnv-voezY5e55HspJFHL8lYenqgXlyFugJEHCnYwKs92MmGLFBNsPhRB3hXdA8ijVWif1sD0Vv8RGTrU6gYBUphzMwbvce3vP4VpWRqmc8-ZXPCDM6r4pq8hxBvih28S2KKTC3p3WN5CslrDXrq2dWLghrRnCXOXGKUDg + client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJoZWRfenhDZjh0QzNzZmxjVzdzZm5JWERkb0tSdnhva21DdnZ3NTZXdGRvIn0.eyJleHAiOjE3MDU0ODAzODEsImlhdCI6MTcwNTM5Mzk4MSwianRpIjoiODVjZmIzMzQtYzFjMi00MGEyLWIzYTItNDQ0MmZkMWNlZmUwIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjdhZGRlZGY0LTRjZjEtNDJjMC04YWI5LTRhMDgwOGQwMTE3OCIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZWNlMWJhNzctMDA0NC00MmFhLTk5OTctNGZlNzg4MWFhYTA0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXSwibmFtZSI6ImZpbmFuY2UgYWRtaW4iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJmaW5hbmNlQG9wZXguZGV2IiwiZ2l2ZW5fbmFtZSI6ImZpbmFuY2UiLCJmYW1pbHlfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJmaW5hbmNlQG9wZXguZGV2In0.o6M37eQZ3O2a6Vf8W8zoRhcqHoanJF2HgcwWprqjJox-eOv6g5xMKA0YtQrwxAm3R_ypdevfy80rmjODKLfYtsM0PI223gdi1lsA24WqdX2yfYoEZpCnTkHLKDqYOn4kJ1Ox0fx-AtLXiwYK40HRCTBXuumu4XDw3JM2edVLr8-eaypY5wudWhN-pymdrUZZn0kDNpdwgSwMGYbVoAsKEBhqdJL5XvR5n3gIKOs3Gv9yQi8MsBln_mq6OUYiObT1cFZh2s0fQcBDXlzzy789ulEKnK1jFpXW5PwkEZPMzsF2AtQxBuRvhscWMsH28fUErezmF-cX53hh8-2d7QITmw + web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e + test-user-username: test1@opex.dev + test-user-password: "12345678" + test-user-email: test1@opex.dev + admin-username: finance@opex.dev + admin-password: "12345678" + user-uuid: 7440dffe-8332-4775-83c2-b5880c526c48 + market-host: https://api.opex.dev/market + super-admin-username: azimi@opex.dev + super-admin-password: Aaswq123 + super-admin-token: "" + bc-gateway-host: https://api.opex.dev/bc-gateway + v2auth-host: https://v2auth.opex.dev + profile-host: https://api.opex.dev/profile + - name: Exky-UAT + meta: + id: env_469269b98298468691dd8f1f8aee80cd + created: 1776684069696 + modified: 1776684101341 + isPrivate: false + sortKey: 1776684069696 + data: + host: https://api-uat.exky.io + api-host: https://api-uat.exky.io/api + auth-host: https://api-uat.exky.io + wallet-host: https://api-uat.exky.io/wallet + admin-host: https://api-uat.exky.io/admin + config-host: https://api-uat.exky.io/config + user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1V20xTXJzMHRjTldmM2NSTHpHNEJseHEzS3JqNUloNGczX2RuWS1uNmpzIn0.eyJleHAiOjE2NDU0NzI0OTIsImlhdCI6MTY0NTQzNjQ5MiwianRpIjoiOTFkYWUxOWMtMTVmZi00ZDJmLWE0ZjItNTMyODFjN2VlMzIyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJlNDUwNWNiOC02ZDcyLTRlY2MtYjhlMC0zNjZhZjM1MmU0YjIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2Vzc2lvbl9zdGF0ZSI6ImIyNmRmNDRkLTY4Y2UtNGQ5NC05YmNkLTlkN2NkYTljMTRkNyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiaW1wZXJzb25hdGlvbiIsImZpbmFuY2UtYWRtaW4iXX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6WyJpbXBlcnNvbmF0aW9uIiwiZmluYW5jZS1hZG1pbiJdLCJuYW1lIjoiZiBmZiIsInByZWZlcnJlZF91c2VybmFtZSI6ImZpbmFuY2UiLCJnaXZlbl9uYW1lIjoiZiIsImZhbWlseV9uYW1lIjoiZmYiLCJlbWFpbCI6ImZpbmFuY2VAZy5jb20ifQ.nS537ox40f2bf4pEVIKgVT8U9FQB9ME4FrtLBH7FOA7R-OzEQmcCgdMayTuRgrpohfygXjaVs_T4xytClNGOR6CTyiGi3Ay7NXzVE-P5JHW9y9catX3VKaS-acNOdtzKvkIvTPS8_0C1jdkRYDLxvPl47lbexbFYQ7a-7J1YNAIQzwRBEPhM-GX1a9mgImH2_mzNtgogLjIvqSNFwWJgnvYaz_Bk_mULsQANVUXk2GSMEDPXAMCTG-TyQXGmxE--rYdEFsy6VIu90sANs3mswtsYo7yeL1T1-jxV8A927FTjBtsGf0KGvV2AjMelMkfm06R1xP0HEVWr_GgmzoLMSg + web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e + test-user-username: demo1 + test-user-password: "12345678" + test-user-email: test@opex.dev + - name: Beta dorost + meta: + id: env_8c4ff57b4a294f50b9579c397e9d31c5 + created: 1776684119860 + modified: 1776684147895 + isPrivate: false + sortKey: 1776684119860 + data: + host: https://api.opex.dev + api-host: https://api.opex.dev/api + auth-host: https://api.opex.dev + wallet-host: https://api.opex.dev/wallet + admin-host: https://api.opex.dev/admin + config-host: https://api.opex.dev/config + user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NTcxNzI1OTMsImlhdCI6MTc1NzE2ODk5MywianRpIjoiYTNjYjJjYWEtMmI1My00YTg1LWI1NDYtM2IyMzBkMDVhNjcxIiwiaXNzIjoiaHR0cDovL2tjLm9wZXguZGV2OjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJvcGV4LWFwaS1rZXkiLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiODdkZjFmMGYtNjhmNy00ZjA4LTgzMjktZjI5MzAxNDEzZTZkIiwic2NvcGUiOiJ0cnVzdCIsImZpcnN0TmFtZSI6Imtvb3Jvc2giLCJsYXN0TmFtZSI6ImF6aW1pIiwicGVybWlzc2lvbnMiOlsiYWxsIiwiZGVwb3NpdDp3cml0ZSJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJzdXBlci1hZG1pbiIsImRlZmF1bHQtcm9sZXMtb3BleCIsImFkbWluIiwidXNlciJdLCJlbWFpbCI6ImF6aW1pQG9wZXguY29tIiwidXNlcm5hbWUiOiJhemltaSJ9.Cy1gtf1YgRlsvA3YK4oVUdQAzOhkom298M5BMGtcKYkddGzzfq69TiIbh3T0jr915NOCEFW0NR38GiWHcA7W1FtRbKDGFNiGSucLBaL0vkmtz0u5L2GWuSQhYVGulFnqka0yCw8tRjWGhsSU3AVghEMwnCwgeeD3Usx9DHp-m-gQ4VJvmHnv-voezY5e55HspJFHL8lYenqgXlyFugJEHCnYwKs92MmGLFBNsPhRB3hXdA8ijVWif1sD0Vv8RGTrU6gYBUphzMwbvce3vP4VpWRqmc8-ZXPCDM6r4pq8hxBvih28S2KKTC3p3WN5CslrDXrq2dWLghrRnCXOXGKUDg + client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA + admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJoZWRfenhDZjh0QzNzZmxjVzdzZm5JWERkb0tSdnhva21DdnZ3NTZXdGRvIn0.eyJleHAiOjE3MDU0ODAzODEsImlhdCI6MTcwNTM5Mzk4MSwianRpIjoiODVjZmIzMzQtYzFjMi00MGEyLWIzYTItNDQ0MmZkMWNlZmUwIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjdhZGRlZGY0LTRjZjEtNDJjMC04YWI5LTRhMDgwOGQwMTE3OCIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZWNlMWJhNzctMDA0NC00MmFhLTk5OTctNGZlNzg4MWFhYTA0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXSwibmFtZSI6ImZpbmFuY2UgYWRtaW4iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJmaW5hbmNlQG9wZXguZGV2IiwiZ2l2ZW5fbmFtZSI6ImZpbmFuY2UiLCJmYW1pbHlfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJmaW5hbmNlQG9wZXguZGV2In0.o6M37eQZ3O2a6Vf8W8zoRhcqHoanJF2HgcwWprqjJox-eOv6g5xMKA0YtQrwxAm3R_ypdevfy80rmjODKLfYtsM0PI223gdi1lsA24WqdX2yfYoEZpCnTkHLKDqYOn4kJ1Ox0fx-AtLXiwYK40HRCTBXuumu4XDw3JM2edVLr8-eaypY5wudWhN-pymdrUZZn0kDNpdwgSwMGYbVoAsKEBhqdJL5XvR5n3gIKOs3Gv9yQi8MsBln_mq6OUYiObT1cFZh2s0fQcBDXlzzy789ulEKnK1jFpXW5PwkEZPMzsF2AtQxBuRvhscWMsH28fUErezmF-cX53hh8-2d7QITmw + web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e + test-user-username: test1@opex.dev + test-user-password: "12345678" + test-user-email: test1@opex.dev + admin-username: finance@opex.dev + admin-password: "12345678" + user-uuid: 7440dffe-8332-4775-83c2-b5880c526c48 + market-host: https://api.opex.dev/market + super-admin-username: azimi@opex.dev + super-admin-password: Aaswq123 + super-admin-token: "" + bc-gateway-host: https://api.opex.dev/bc-gateway + v2auth-host: https://v2auth.opex.dev + profile-host: https://api.opex.dev/profile diff --git a/accountant/accountant-app/src/main/resources/application.yml b/accountant/accountant-app/src/main/resources/application.yml index a2b0499a6..d4a8b64f2 100644 --- a/accountant/accountant-app/src/main/resources/application.yml +++ b/accountant/accountant-app/src/main/resources/application.yml @@ -112,3 +112,12 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + + +# --- Swagger / SpringDoc (env-driven) --- +springdoc: + api-docs: + enabled: ${SWAGGER_API_DOCS_ENABLED:false} + swagger-ui: + enabled: ${SWAGGER_UI_ENABLED:false} + path: ${SWAGGER_UI_PATH:/swagger-ui.html} diff --git a/api.csv b/api.csv new file mode 100644 index 000000000..f40a56206 --- /dev/null +++ b/api.csv @@ -0,0 +1,31 @@ +Public API Path,Internal Module Path,Method,Module,Through API Layer,Auth Required,Roles/Permissions,Controller,Notes +/opex/v1/address-book,UNKNOWN,POST,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.addAddressBook(token, request) +/opex/v1/address-book,UNKNOWN,GET,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.getAllAddressBooks(token) +/opex/v1/address-book/{id},UNKNOWN,DELETE,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.deleteAddressBook(token, id) +/opex/v1/address-book/{id},UNKNOWN,PUT,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.updateAddressBook(token, id, request) +/opex/v1/admin/storage,UNKNOWN,GET,storage,YES,YES,ADMIN? (NEEDS REVIEW),StorageAdminController,Download file by bucket/key +/opex/v1/admin/storage,UNKNOWN,POST,storage,YES,YES,ADMIN? (NEEDS REVIEW),StorageAdminController,Upload multipart file; returns URL +/opex/v1/admin/storage,UNKNOWN,DELETE,storage,YES,YES,ADMIN? (NEEDS REVIEW),StorageAdminController,Delete file by bucket/key +/opex/v1/withdraw,UNKNOWN,POST,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Request withdraw +/opex/v1/withdraw/{withdrawUuid}/cancel,UNKNOWN,PUT,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Cancel withdraw +/opex/v1/withdraw/{withdrawUuid},UNKNOWN,GET,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Find withdraw +/opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request,UNKNOWN,POST,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Request withdraw OTP +/opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify,UNKNOWN,POST,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Verify withdraw OTP (otpCode as query) +/opex/v1/deposit,UNKNOWN,POST,wallet-app,YES,NOT CLEAR,NOT CLEAR,DepositController,Security not explicit at controller; verify upstream security +/opex/v1/admin/wallet/users,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),WalletAdminController,List users wallets +/opex/v1/admin/wallet/system/total,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),WalletAdminController,System wallets total +/opex/v1/admin/wallet/users/total,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),WalletAdminController,Users wallets total +/opex/v1/voucher/{code},UNKNOWN,PUT,wallet-app,YES,YES,USER (implicit),VoucherController,Submit voucher using token +/opex/v1/user/data/trade/volume,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Requires symbol and interval +/opex/v1/user/data/trade/volume/total,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Requires interval +/opex/v1/user/data/fee,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Returns UserFee +/opex/v1/user/data/withdraw/volume/total,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Optional interval string mapped to enum +/opex/v1/admin/currency/{currency}/localization,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Get currency localization +/opex/v1/admin/currency/{currency}/localization,UNKNOWN,POST,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Save currency localizations +/opex/v1/admin/currency/localization/{id},UNKNOWN,DELETE,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Delete currency localization by id +/opex/v1/admin/terminal/{terminalUuid}/localization,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Get terminal localization +/opex/v1/admin/terminal/{terminalUuid}/localization,UNKNOWN,POST,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Save terminal localizations +/opex/v1/admin/terminal/localization/{id},UNKNOWN,DELETE,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Delete terminal localization by id +/opex/v1/admin/gateway/{gatewayUuid}/localization,UNKNOWN,GET,MIXED(wallet-app;bc-gateway-app),YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,If uuid starts with ofg → wallet; ong → bc-gateway +/opex/v1/admin/gateway/{gatewayUuid}/localization,UNKNOWN,POST,MIXED(wallet-app;bc-gateway-app),YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,If uuid starts with ofg → wallet; ong → bc-gateway +/opex/v1/admin/gateway/{gatewayUuid}/localization/{id},UNKNOWN,DELETE,MIXED(wallet-app;bc-gateway-app),YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,If uuid starts with ofg → wallet; ong → bc-gateway diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 75e48f9e2..a3faf1697 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -147,3 +147,12 @@ app: key: ${api_crypto_key:0e1fd29572ec8c85970d76e3433e96ee} swagger: authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token + + +# --- Swagger / SpringDoc (env-driven) --- +springdoc: + api-docs: + enabled: ${SWAGGER_API_DOCS_ENABLED:false} + swagger-ui: + enabled: ${SWAGGER_UI_ENABLED:false} + path: ${SWAGGER_UI_PATH:/swagger-ui.html} diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt index 8528dfabf..b4c91df93 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt @@ -33,8 +33,7 @@ class SecurityConfig( return http.csrf { it.disable() } .authorizeExchange { it.pathMatchers("/actuator/**").permitAll() - .pathMatchers("/swagger-ui/**").permitAll() - .pathMatchers("/swagger-resources/**").permitAll() + .pathMatchers("/swagger-ui.html").permitAll() .pathMatchers("/v1/rate-limit").hasAuthority("ROLE_admin") .pathMatchers("/v2/api-docs").permitAll() .pathMatchers("/v3/depth").permitAll() diff --git a/api/api-ports/api-opex-rest/pom.xml b/api/api-ports/api-opex-rest/pom.xml index 0e857f35c..7c2a9442b 100644 --- a/api/api-ports/api-opex-rest/pom.xml +++ b/api/api-ports/api-opex-rest/pom.xml @@ -66,10 +66,24 @@ reactor-test test + - io.swagger + io.swagger.core.v3 swagger-annotations - 1.5.20 + 2.2.15 + + + + org.springdoc + springdoc-openapi-webflux-ui + 1.7.0 + + + + central + https://repo1.maven.org/maven2/ + + diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt index 369111929..21783e070 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt @@ -5,17 +5,43 @@ import co.nilin.opex.api.core.inout.AddressBookResponse import co.nilin.opex.api.core.spi.ProfileProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/address-book") +@Tag(name = "Address Book", description = "Manage user address book entries") class AddressBookController( val profileProxy: ProfileProxy, ) { @PostMapping + @Operation( + summary = "Add address book entry", + description = "Creates a new address book entry for the authenticated user.", + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content(mediaType = "application/json", schema = Schema(implementation = AddAddressBookItemRequest::class))] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Created/Updated", + content = [Content(mediaType = "application/json", schema = Schema(implementation = AddressBookResponse::class))] + ) + ] + ) suspend fun addAddressBook( @RequestBody request: AddAddressBookItemRequest, @CurrentSecurityContext securityContext: SecurityContext @@ -24,11 +50,34 @@ class AddressBookController( } @GetMapping + @Operation( + summary = "List address book entries", + description = "Returns all address book entries for the authenticated user.", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "OK", + content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = AddressBookResponse::class)))] + ) + ] + ) suspend fun getAddressBook(@CurrentSecurityContext securityContext: SecurityContext): List { return profileProxy.getAllAddressBooks(securityContext.jwtAuthentication().tokenValue()) } @DeleteMapping("/{id}") + @Operation( + summary = "Delete address book entry", + description = "Deletes an address book entry by id.", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) + ], + responses = [ + ApiResponse(responseCode = "200", description = "Deleted") + ] + ) suspend fun deleteAddressBook( @PathVariable("id") id: Long, @CurrentSecurityContext securityContext: SecurityContext @@ -37,6 +86,25 @@ class AddressBookController( } @PutMapping("/{id}") + @Operation( + summary = "Update address book entry", + description = "Updates an existing address book entry by id.", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) + ], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content(mediaType = "application/json", schema = Schema(implementation = AddAddressBookItemRequest::class))] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "OK", + content = [Content(mediaType = "application/json", schema = Schema(implementation = AddressBookResponse::class))] + ) + ] + ) suspend fun updateAddressBook( @PathVariable("id") id: Long, @RequestBody request: AddAddressBookItemRequest, diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt index e704894c7..4acfeb6d3 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -5,17 +5,40 @@ import co.nilin.opex.api.core.inout.BankAccountResponse import co.nilin.opex.api.core.spi.ProfileProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/bank-account") +@Tag(name = "Bank Account", description = "Manage user bank accounts") class BankAccountController( val profileProxy: ProfileProxy, ) { @PostMapping + @Operation( + summary = "Add bank account", + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content(mediaType = "application/json", schema = Schema(implementation = AddBankAccountRequest::class))] + ), + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class)) + ]) + ] + ) suspend fun addBankAccount( @RequestBody request: AddBankAccountRequest, @CurrentSecurityContext securityContext: SecurityContext @@ -24,11 +47,28 @@ class BankAccountController( } @GetMapping + @Operation( + summary = "List bank accounts", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class))) + ]) + ] + ) suspend fun getBankAccounts(@CurrentSecurityContext securityContext: SecurityContext): List { return profileProxy.getBankAccounts(securityContext.jwtAuthentication().tokenValue()) } @DeleteMapping("/{id}") + @Operation( + summary = "Delete bank account", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) + ], + responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + ) suspend fun deleteBankAccount( @PathVariable("id") id: Long, @CurrentSecurityContext securityContext: SecurityContext diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt index fd055219b..930441184 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt @@ -3,6 +3,11 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.RequestDepositBody import co.nilin.opex.api.core.inout.TransferResult import co.nilin.opex.api.core.spi.WalletProxy +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping @@ -10,9 +15,23 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/deposit") +@Tag(name = "Deposit", description = "Deposit operations") class DepositController(private val walletProxy: WalletProxy) { @PostMapping + @Operation( + summary = "Request deposit", + description = "Submit a deposit request. Security handling is upstream (NEEDS REVIEW).", + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content(mediaType = "application/json", schema = Schema(implementation = RequestDepositBody::class))] + ), + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class)) + ]) + ] + ) suspend fun deposit(@RequestBody request: RequestDepositBody): TransferResult? { return walletProxy.deposit(request) } diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt index dcb038f74..c13801ee7 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt @@ -6,17 +6,35 @@ import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue import co.nilin.opex.common.OpexError +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/admin") +@Tag(name = "Localization Admin", description = "Admin localization management for currencies, terminals, and gateways") class LocalizationAdminController( private val walletProxy: WalletProxy, private val blockchainGatewayProxy: BlockchainGatewayProxy ) { @GetMapping("/currency/{currency}/localization") + @Operation( + summary = "Admin: get currency localizations", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "currency", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) + ], + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = CurrencyLocalizationResponse::class)) ]) ] + ) suspend fun getCurrencyLocalizations( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currency") currency: String @@ -25,6 +43,13 @@ class LocalizationAdminController( } @PostMapping("/currency/{currency}/localization") + @Operation( + summary = "Admin: save currency localizations", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ Parameter(name = "currency", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyLocalizationCommand::class))) ]), + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = CurrencyLocalizationResponse::class)) ]) ] + ) suspend fun saveCurrencyLocalizations( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currency") currency: String, @@ -38,6 +63,12 @@ class LocalizationAdminController( } @DeleteMapping("/currency/localization/{id}") + @Operation( + summary = "Admin: delete currency localization", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) ], + responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + ) suspend fun deleteCurrencyLocalization( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("id") id: Long @@ -46,6 +77,12 @@ class LocalizationAdminController( } @GetMapping("/terminal/{terminalUuid}/localization") + @Operation( + summary = "Admin: get terminal localizations", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ Parameter(name = "terminalUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = TerminalLocalizationResponse::class)) ]) ] + ) suspend fun getTerminalLocalizations( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("terminalUuid") terminalUuid: String @@ -54,6 +91,13 @@ class LocalizationAdminController( } @PostMapping("/terminal/{terminalUuid}/localization") + @Operation( + summary = "Admin: save terminal localizations", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ Parameter(name = "terminalUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = TerminalLocalizationCommand::class))) ]), + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = TerminalLocalizationResponse::class)) ]) ] + ) suspend fun saveTerminalLocalizations( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("terminalUuid") terminalUuid: String, @@ -67,6 +111,12 @@ class LocalizationAdminController( } @DeleteMapping("/terminal/localization/{id}") + @Operation( + summary = "Admin: delete terminal localization", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) ], + responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + ) suspend fun deleteTerminalLocalization( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("id") id: Long @@ -75,6 +125,12 @@ class LocalizationAdminController( } @GetMapping("/gateway/{gatewayUuid}/localization") + @Operation( + summary = "Admin: get gateway localization", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ Parameter(name = "gatewayUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = GatewayLocalizationResponse::class)) ]) ] + ) suspend fun getGatewayLocalization( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("gatewayUuid") gatewayUuid: String @@ -92,6 +148,13 @@ class LocalizationAdminController( } @PostMapping("/gateway/{gatewayUuid}/localization") + @Operation( + summary = "Admin: save gateway localizations", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ Parameter(name = "gatewayUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = GatewayLocalizationCommand::class))) ]), + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = GatewayLocalizationResponse::class)) ]) ] + ) suspend fun saveGatewayLocalizations( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("gatewayUuid") gatewayUuid: String, @@ -113,6 +176,15 @@ class LocalizationAdminController( } @DeleteMapping("/gateway/{gatewayUuid}/localization/{id}") + @Operation( + summary = "Admin: delete gateway localization", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "gatewayUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")), + Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) + ], + responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + ) suspend fun deleteGatewayLocalization( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("id") id: Long, diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt index db9cf0c90..7e379e03c 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt @@ -10,7 +10,7 @@ import co.nilin.opex.api.ports.opex.util.* import co.nilin.opex.common.OpexError import co.nilin.opex.common.security.jwtAuthentication import co.nilin.opex.common.security.tokenValue -import io.swagger.annotations.ApiParam +import io.swagger.v3.oas.annotations.Parameter import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @@ -41,7 +41,7 @@ class OrderController( quoteOrderQty: BigDecimal?, @RequestParam(required = false) price: BigDecimal?, - @ApiParam(value = "Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.") + @Parameter(description = "Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.") @RequestParam(required = false) stopPrice: BigDecimal?, @CurrentSecurityContext securityContext: SecurityContext diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt index 3481f3ac5..18dded9a0 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt @@ -3,6 +3,14 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.spi.StorageProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.beans.factory.annotation.Value import org.springframework.http.ResponseEntity import org.springframework.http.codec.multipart.FilePart @@ -12,12 +20,29 @@ import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/admin/storage") +@Tag(name = "Storage Admin", description = "Admin operations for storage service") class StorageAdminController( private val storageProxy: StorageProxy, @Value("\${app.base.url}") private val appBaseUrl: String ) { @GetMapping + @Operation( + summary = "Admin: download file", + description = "Download a file by bucket and key.", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "bucket", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), + Parameter(name = "key", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "OK", + content = [Content(mediaType = "application/octet-stream", schema = Schema(type = "string", format = "binary"))] + ) + ] + ) suspend fun download( @CurrentSecurityContext securityContext: SecurityContext, @RequestParam("bucket") bucket: String, @@ -27,6 +52,23 @@ class StorageAdminController( } @PostMapping + @Operation( + summary = "Admin: upload file", + description = "Upload a file to a bucket with a specific key.", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "bucket", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), + Parameter(name = "key", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), + Parameter(name = "isPublic", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "boolean")) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "OK", + content = [Content(mediaType = "text/plain", schema = Schema(type = "string"))] + ) + ] + ) suspend fun upload( @CurrentSecurityContext securityContext: SecurityContext, @RequestParam("bucket") bucket: String, @@ -39,6 +81,18 @@ class StorageAdminController( } @DeleteMapping + @Operation( + summary = "Admin: delete file", + description = "Delete a file by bucket and key.", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "bucket", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), + Parameter(name = "key", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")) + ], + responses = [ + ApiResponse(responseCode = "200", description = "Deleted") + ] + ) suspend fun delete( @CurrentSecurityContext securityContext: SecurityContext, @RequestParam("bucket") bucket: String, diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt index 4be17e6f7..15e20a2e2 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt @@ -4,6 +4,14 @@ import co.nilin.opex.api.core.inout.UserFee import co.nilin.opex.api.core.spi.AccountantProxy import co.nilin.opex.common.OpexError import co.nilin.opex.common.utils.Interval +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.GetMapping @@ -14,11 +22,21 @@ import java.math.BigDecimal @RestController @RequestMapping("/opex/v1/user/data") +@Tag(name = "User Data", description = "Authenticated user data endpoints") class UserDataController( private val accountantProxy: AccountantProxy, ) { @GetMapping("/trade/volume") + @Operation( + summary = "Get user trade volume by currency", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "symbol", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), + Parameter(name = "interval", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string", description = "Interval: Day|Week|Month|Year")) + ], + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(type = "number", format = "double")) ]) ] + ) suspend fun getTradeVolumeByCurrency( @CurrentSecurityContext securityContext: SecurityContext, @RequestParam symbol: String, @@ -30,6 +48,14 @@ class UserDataController( } @GetMapping("/trade/volume/total") + @Operation( + summary = "Get user total trade volume value", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "interval", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string", description = "Interval: Day|Week|Month|Year")) + ], + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(type = "number", format = "double")) ]) ] + ) suspend fun getTotalTradeVolumeValue( @CurrentSecurityContext securityContext: SecurityContext, @RequestParam interval: Interval @@ -40,11 +66,24 @@ class UserDataController( } @GetMapping("/fee") + @Operation( + summary = "Get user fee settings", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = UserFee::class)) ]) ] + ) suspend fun getUserFee(@CurrentSecurityContext securityContext: SecurityContext): UserFee { return accountantProxy.getUserFee(securityContext.authentication.name) } @GetMapping("/withdraw/volume/total") + @Operation( + summary = "Get user total withdraw volume value", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "interval", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string", description = "Optional label; maps to Interval by label")) + ], + responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(type = "number", format = "double")) ]) ] + ) suspend fun getTotalWithdrawVolumeValue( @CurrentSecurityContext securityContext: SecurityContext, @RequestParam(required = false) interval: String? diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt index 50c7800ec..ddabb2fac 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt @@ -3,20 +3,41 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.SubmitVoucherResponse import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.common.security.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PutMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController -import co.nilin.opex.api.ports.opex.util.tokenValue @RestController @RequestMapping("/opex/v1/voucher") +@Tag(name = "Voucher", description = "Voucher submission operations") class VoucherController(private val walletProxy: WalletProxy) { @PutMapping("/{code}") + @Operation( + summary = "Submit voucher code", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "code", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) + ], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", schema = Schema(implementation = SubmitVoucherResponse::class)) + ]) + ] + ) suspend fun submitVoucher( @PathVariable code: String, @CurrentSecurityContext securityContext: SecurityContext diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt index a0ab52916..25f6179ca 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt @@ -5,6 +5,15 @@ import co.nilin.opex.api.core.inout.WalletTotal import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.GetMapping @@ -14,11 +23,28 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/admin/wallet") +@Tag(name = "Wallet Admin", description = "Admin operations on wallets") class WalletAdminController( private val walletProxy: WalletProxy ) { @GetMapping("/users") + @Operation( + summary = "Admin: List users wallets", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "uuid", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string")), + Parameter(name = "currency", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string")), + Parameter(name = "excludeSystem", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "boolean", defaultValue = "false")), + Parameter(name = "limit", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "integer", defaultValue = "10")), + Parameter(name = "offset", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "integer", defaultValue = "0")) + ], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletDataResponse::class))) + ]) + ] + ) suspend fun getUsersWallets( @CurrentSecurityContext securityContext: SecurityContext, @RequestParam(required = false) uuid: String?, @@ -38,11 +64,29 @@ class WalletAdminController( } @GetMapping("/system/total") + @Operation( + summary = "Admin: System wallets total", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletTotal::class))) + ]) + ] + ) suspend fun getSystemWalletsTotal(@CurrentSecurityContext securityContext: SecurityContext): List { return walletProxy.getSystemWalletsTotal(securityContext.jwtAuthentication().tokenValue()) } @GetMapping("/users/total") + @Operation( + summary = "Admin: Users wallets total", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletTotal::class))) + ]) + ] + ) suspend fun getUsersWalletsTotal(@CurrentSecurityContext securityContext: SecurityContext): List? { return walletProxy.getUsersWalletsTotal(securityContext.jwtAuthentication().tokenValue()) } diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt index 5cde9598a..b06d07a93 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt @@ -4,17 +4,39 @@ import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/withdraw") +@Tag(name = "Withdraw", description = "User withdrawal operations") class WithdrawController( private val walletProxy: WalletProxy, ) { @PostMapping + @Operation( + summary = "Request withdraw", + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content(mediaType = "application/json", schema = Schema(implementation = RequestWithdrawBody::class))] + ), + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", schema = Schema(implementation = WithdrawActionResult::class)) + ]) + ] + ) suspend fun requestWithdraw( @CurrentSecurityContext securityContext: SecurityContext, @RequestBody request: RequestWithdrawBody @@ -26,6 +48,14 @@ class WithdrawController( } @PutMapping("/{withdrawUuid}/cancel") + @Operation( + summary = "Cancel withdraw", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) + ], + responses = [ ApiResponse(responseCode = "200", description = "Cancelled") ] + ) suspend fun cancelWithdraw( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable withdrawUuid: String @@ -37,6 +67,18 @@ class WithdrawController( } @GetMapping("/{withdrawUuid}") + @Operation( + summary = "Find withdraw", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) + ], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", schema = Schema(implementation = WithdrawResponse::class)) + ]) + ] + ) suspend fun findWithdraw( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable withdrawUuid: String @@ -48,6 +90,19 @@ class WithdrawController( } @PostMapping("/{withdrawUuid}/otp/{otpType}/request") + @Operation( + summary = "Request withdraw OTP", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")), + Parameter(name = "otpType", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string", description = "OTPType")) + ], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", schema = Schema(implementation = TempOtpResponse::class)) + ]) + ] + ) suspend fun requestOTP( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable withdrawUuid: String, @@ -57,6 +112,20 @@ class WithdrawController( } @PostMapping("/{withdrawUuid}/otp/{otpType}/verify") + @Operation( + summary = "Verify withdraw OTP", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")), + Parameter(name = "otpType", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string", description = "OTPType")), + Parameter(name = "otpCode", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")) + ], + responses = [ + ApiResponse(responseCode = "200", description = "OK", content = [ + Content(mediaType = "application/json", schema = Schema(implementation = WithdrawActionResult::class)) + ]) + ] + ) suspend fun verifyOTP( @CurrentSecurityContext securityContext: SecurityContext, @PathVariable withdrawUuid: String, diff --git a/auth-gateway/auth-gateway-app/src/main/resources/application.yml b/auth-gateway/auth-gateway-app/src/main/resources/application.yml index 3948349e6..27413cfdf 100644 --- a/auth-gateway/auth-gateway-app/src/main/resources/application.yml +++ b/auth-gateway/auth-gateway-app/src/main/resources/application.yml @@ -78,3 +78,12 @@ app: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} pre-auth-client-secret: ${PRE_AUTH_CLIENT_SECRET} + + +# --- Swagger / SpringDoc (env-driven) --- +springdoc: + api-docs: + enabled: ${SWAGGER_API_DOCS_ENABLED:false} + swagger-ui: + enabled: ${SWAGGER_UI_ENABLED:false} + path: ${SWAGGER_UI_PATH:/swagger-ui.html} From d3b4a4da914af7a20c1dadf05ceb02e22cf2addd Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sun, 10 May 2026 20:12:13 +0330 Subject: [PATCH 02/56] RM unused files --- .gitignore | 2 +- Insomnia_2026-05-10.yaml | 11217 ------------------------------------- 2 files changed, 1 insertion(+), 11218 deletions(-) delete mode 100644 Insomnia_2026-05-10.yaml diff --git a/.gitignore b/.gitignore index 0e7dc419c..e27020d7c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/ - +./api.csv ### STS ### .apt_generated .classpath diff --git a/Insomnia_2026-05-10.yaml b/Insomnia_2026-05-10.yaml deleted file mode 100644 index 58d49b9c8..000000000 --- a/Insomnia_2026-05-10.yaml +++ /dev/null @@ -1,11217 +0,0 @@ -type: collection.insomnia.rest/5.0 -schema_version: "5.1" -name: opex -meta: - id: wrk_7773a4a08dff402f8029ba5d5ac718a8 - created: 1776614688089 - modified: 1776614688089 - description: "" -collection: - - name: Opex - meta: - id: fld_c35b513ad37d4fba9464eec8cb135511 - created: 1776615524558 - modified: 1776615524558 - sortKey: -1776615518731 - description: "" - children: - - name: Auth - meta: - id: fld_b017250d23614bfb94f4ba7308bff501 - created: 1776615524560 - modified: 1778084645873 - sortKey: -1776615518730 - description: "" - children: - - url: "{{_['host']}}/storage/-/09a56d8b-f364-4c88-8f8d-3b0a52e72080" - name: Send User File - meta: - id: req_5bd31092fbe44bafad8a1a944f2de465 - created: 1776615524610 - modified: 1776615524610 - isPrivate: false - description: "" - sortKey: -1776615518690 - method: POST - body: - mimeType: multipart/form-data - params: - - name: file - disabled: false - fileName: /C:/Users/Ben/Downloads/overview.jpg - type: file - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['host']}}/storage/-/09a56d8b-f364-4c88-8f8d-3b0a52e72080/overview.jpg" - name: Get User File - meta: - id: req_9f1152e3406849428d02a86c49335426 - created: 1776615524611 - modified: 1776615524611 - isPrivate: false - description: "" - sortKey: -1776615518689 - method: GET - body: - mimeType: multipart/form-data - params: - - name: file - disabled: false - fileName: /C:/Users/Ben/Downloads/overview.jpg - type: file - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{host}}/captcha/generate" - name: Request captcha - meta: - id: req_2229af380bd3414daad8b6d54847c36a - created: 1776615524613 - modified: 1776615524613 - isPrivate: false - description: "" - sortKey: -1776615518688 - method: POST - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: User Registration - meta: - id: fld_ead6fdd431d84b2da146ea0cd3291bba - created: 1776615524562 - modified: 1776615524562 - sortKey: -1776615518729 - description: "" - children: - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user" - name: Create User - meta: - id: req_1133bb24d3504139bf9d7d0b91774b79 - created: 1776615524564 - modified: 1776615534993 - isPrivate: false - description: "" - sortKey: -1776615518728 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"firstName\":\"t4\",\r - - \ \"lastName\":\"tt4\",\r - - \ \"email\":\"test4@gmail.com\",\r - - \ \"password\":\"11111111\",\r - - \ \"passwordConfirmation\":\"11111111\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['client-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user" - name: Create User with Captcha - meta: - id: req_53681726c84f4f1fa64ac79ad4de268a - created: 1776615524567 - modified: 1776615524567 - isPrivate: false - description: "" - sortKey: -1776615518727 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"firstName\":\"test-dtesjیddt1\",\r - - \ \"lastName\":\"test-dtedstیd1j\",\r - - \ \"email\":\"tedst1jt@gdmaiیl.com\",\r - - \ \"username\":\"tesddt_jtیesdt_tets1\",\r - - \ \"captchaAnswer\" : - \"44b95b4fa17a57ca1db2c80be5bc0994f4b6489f110740ce8b9f302b6\ - f4865c8-0b63c250\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['client-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/request-verify" - name: Request Verify Email - meta: - id: req_f8a1d740ad9942cab1913fe6408550fa - created: 1776615524569 - modified: 1776615524569 - isPrivate: false - description: "" - sortKey: -1776615518726 - method: POST - parameters: - - name: email - value: test@opex.dev - disabled: false - - name: captcha - value: 06aecbb42146f3fdc441c804677e283718c14b7fad4656a6de6faa67da729044-7a368 - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/request-forgot" - name: Request Forgot Password - meta: - id: req_da8b75f0ef6b4282846bf7c332678fb8 - created: 1776615524570 - modified: 1776615524570 - isPrivate: false - description: "" - sortKey: -1776615518725 - method: POST - parameters: - - name: email - value: test@opex.dev - disabled: false - - name: captcha - value: "145236" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/forgot" - name: Forgot Password - meta: - id: req_170f302d5fb14adb87f54ca27de0e9e9 - created: 1776615524572 - modified: 1776615524572 - isPrivate: false - description: "" - sortKey: -1776615518724 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"password\": \"12312312\",\r - - \ \"passwordConfirmation\": \"12312312\"\r - - }" - parameters: - - name: key - value: eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhNmRhYWUyOC1hNzZiLTQzNGEtOTY3My04MzQyOWJiNGNiNDUifQ.eyJleHAiOjE2NjEyMDE1MzEsImlhdCI6MTY2MTE1ODMzMSwianRpIjoiOWRlOTNjNjEtOTU0Zi00YWI5LWJiZjMtODE3NjAxMzAwNDBkIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwODMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjFlMzRlYjNlLTE1NzctNDQyNC1hMDdkLWIxYmM0MjcwY2JjOSIsInR5cCI6ImV4ZWN1dGUtYWN0aW9ucyIsImF6cCI6ImFjY291bnQiLCJub25jZSI6IjlkZTkzYzYxLTk1NGYtNGFiOS1iYmYzLTgxNzYwMTMwMDQwZCIsInJlZHVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC91c2VyL3ZlcmlmeSIsInJxYWMiOlsiVVBEQVRFX1BBU1NXT1JEIl0sInJxYWMiOlsiVVBEQVRFX1BBU1NXT1JEIl0sInJlZHVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC91c2VyL3ZlcmlmeSJ9.-upcDJO6eclBX_XCgakZEbCBlkKOMBqlbNR3tcssGLg - disabled: false - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Login - meta: - id: fld_ce00ddfb60ae483dbf5c5c0ff778d15c - created: 1776615524573 - modified: 1776615524573 - sortKey: -1776615518723 - description: "" - children: - - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" - name: Get Access Token for Web App Client - meta: - id: req_8e9a118000434c2dbc0c99b8e10d7540 - created: 1776615524574 - modified: 1778083333128 - isPrivate: false - description: "" - sortKey: -1776615518722 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_id - value: web-app - disabled: false - - name: client_secret - value: "{{_['web-app-secret']}}" - disabled: false - - name: grant_type - value: client_credentials - disabled: false - headers: - - name: Content-TypeCo - value: application/jsonapplication/x-www-form-urlencoded - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" - name: Get Access Token for user Web App - meta: - id: req_df379c78d1044eff9029b976ec42da74 - created: 1776615524575 - modified: 1776615524575 - isPrivate: false - description: "" - sortKey: -1776615518721 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_id - value: web-app - disabled: false - - name: username - value: "{{_['test-user-email']}}" - disabled: false - - name: password - value: "{{_['test-user-password']}}" - disabled: false - - name: grant_type - value: password - disabled: false - - name: client_secret - value: "{{_['web-app-secret']}}" - disabled: false - - name: agent - value: postman - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" - name: Get Access Token for admin Web App - meta: - id: req_87f74cee5d21468e9d68bee231ebc2b2 - created: 1776615524576 - modified: 1776615524576 - isPrivate: false - description: "" - sortKey: -1776615518720 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_id - value: web-app - disabled: false - - name: username - value: "{{_['admin-username']}}" - disabled: false - - name: password - value: "{{_['admin-password']}}" - disabled: false - - name: grant_type - value: password - disabled: false - - name: client_secret - value: "{{_['web-app-secret']}}" - disabled: false - - name: agent - value: postman - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - scripts: - afterResponse: "let admin_token=insomnia.response.json().access_token;\r - - insomnia.environment.set(\"admin-token\", admin_token);" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" - name: Get Access Token for super admin Web App - meta: - id: req_3a8a8e6388e0416786f65ed7ece27a71 - created: 1776615524577 - modified: 1776615524577 - isPrivate: false - description: "" - sortKey: -1776615518719 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_id - value: web-app - disabled: false - - name: username - value: "{{_['super-admin-username']}}" - disabled: false - - name: password - value: "{{_['super-admin-password']}}" - disabled: false - - name: grant_type - value: password - disabled: false - - name: client_secret - value: "{{_['web-app-secret']}}" - disabled: false - - name: agent - value: postman - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - scripts: - afterResponse: "let super_admin_token=insomnia.response.json().access_token;\r - - insomnia.environment.set(\"super-admin-token\",super_admin_\ - token);" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "" - name: Get Access Token for user Web App (OTP Enabled) - meta: - id: req_d2633e85649f47f1948a611b3c8ed87a - created: 1776615524579 - modified: 1776615524579 - isPrivate: false - description: "" - sortKey: -1776615518718 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" - name: Refresh Access Token - meta: - id: req_12b181d3503c4f74bc52d6b16ec01352 - created: 1776615524582 - modified: 1776615524582 - isPrivate: false - description: "" - sortKey: -1776615518717 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_secret - value: "{{_['web-app-secret']}}" - disabled: false - - name: client_id - value: web-app - disabled: false - - name: grant_type - value: refresh_token - disabled: false - - name: refresh_token - value: eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMGZmOTk4Mi0xNzhlLTQ5MTAtYjFhNi0yYzdiNTVlYTIzMTYifQ.eyJleHAiOjE2NDY2NTYyODAsImlhdCI6MTY0NjY1NDQ4MCwianRpIjoiNWU1OGYxN2EtZTZhOS00ZDU4LWI0YjgtODgwOGRmZDMwNzg4IiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2L2F1dGgvcmVhbG1zL29wZXgiLCJhdWQiOiJodHRwczovL2RlbW8ub3BleC5kZXYvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6Ijc3YmI4OWMyLWJkYjYtNDc0MS1hYzc1LTY1NTA2YWVjNWU3NCIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJ3ZWItYXBwIiwic2Vzc2lvbl9zdGF0ZSI6IjI2ZGQ4MWY4LTBjNGUtNDFhMy04YThmLTBiNDVlMjVkOTc0MyIsInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCJ9.6h_t7mFHYbBSbasmJgSJSWTR10WsqYMOnuXMhuOep_4 - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://demo.opex.dev/auth/realms/opex/user-management/user/forgot - name: Forgot Password - meta: - id: req_49b96ce4b6fe489e834fa793333259fa - created: 1776615524583 - modified: 1776615524583 - isPrivate: false - description: "" - sortKey: -1776615518716 - method: POST - parameters: - - name: email - value: "{{_['test-user-email']}}" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/logout" - name: Logout - meta: - id: req_e1ca37e6000d4a1fb8a483cce8a91858 - created: 1776615524585 - modified: 1776615524585 - isPrivate: false - description: "" - sortKey: -1776615518715 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/sessions/42c9500\ - 8-5bf6-4eb3-b33c-7635fd1dc8a5/logout" - name: "Logout Using Session Id " - meta: - id: req_a3bad3159e224371a248828d036d208e - created: 1776615524586 - modified: 1776615524586 - isPrivate: false - description: "" - sortKey: -1776615518714 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/sessions/logout" - name: Logout All Sessions Except Current - meta: - id: req_1712ca2f2dc04a01bfc37b70e6d83089 - created: 1776615524587 - modified: 1776615524587 - isPrivate: false - description: "" - sortKey: -1776615518713 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Security - meta: - id: fld_9fc89e0a39ff4793acf8a4691f8cc458 - created: 1776615524589 - modified: 1776615524589 - sortKey: -1776615518712 - description: "" - children: - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/check" - name: Check User Security Configs - meta: - id: req_2a4404ac0aa04d80b1eaf428bed04b80 - created: 1776615524590 - modified: 1776615524590 - isPrivate: false - description: "" - sortKey: -1776615518711 - method: GET - parameters: - - name: username - value: demo5 - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['client-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" - name: "Request Activate OTP " - meta: - id: req_05bad77c39f34e0084f7826fdde35277 - created: 1776615524591 - modified: 1776615524591 - isPrivate: false - description: "" - sortKey: -1776615518710 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/captcha/session" - name: captcha - meta: - id: req_0bd8474f77cf47ad941780142ccde3d4 - created: 1776615524592 - modified: 1776615524592 - isPrivate: false - description: "" - sortKey: -1776615518709 - method: POST - headers: - - name: Content-Type - value: image/jpeg - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" - name: verify captcha - meta: - id: req_f78e4d836bad4af39beda77157a6cf83 - created: 1776615524593 - modified: 1776615524593 - isPrivate: false - description: "" - sortKey: -1776615518708 - method: GET - headers: - - name: Content-Type - value: image/jpeg - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" - name: Activate OTP - meta: - id: req_ff44a6eb7fb24e2f969f5ddf71ea232f - created: 1776615524594 - modified: 1776615524594 - isPrivate: false - description: "" - sortKey: -1776615518707 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"secret\":\"3yFcfhruTNomR9lBMOCks4HSVui2djvw0owN7Qa0O\ - gqqlllWAaluKUeDxIfDRSSK\",\r - - \ \"initialCode\":\"472749\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/otp" - name: Disable OTP - meta: - id: req_6ff31fea8c9144ffb27b54c7c519aaa5 - created: 1776615524595 - modified: 1776615524595 - isPrivate: false - description: "" - sortKey: -1776615518706 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/security/passwor\ - d" - name: Change Password - meta: - id: req_2adc6df3a5fb477381b62ceb61d07abc - created: 1776615524597 - modified: 1776615524597 - isPrivate: false - description: "" - sortKey: -1776615518705 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"password\":\"demo1\",\r - - \ \"newPassword\":\"12345\",\r - - \ \"confirmation\":\"12345\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/user-management/user/sessions" - name: Get Sessions - meta: - id: req_f463b77cb9a74cf4833c5ab4fadac21c - created: 1776615524598 - modified: 1776615524598 - isPrivate: false - description: "" - sortKey: -1776615518704 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: _depricated - meta: - id: fld_c20237e206f843cbb3ec48ea733fc3a1 - created: 1776615524599 - modified: 1776615524599 - sortKey: -1776615518703 - description: "" - children: - - url: https://api.opex.dev/auth/realms/opex/protocol/openid-connect/token - name: Get Access Token for Client ( expired ) - meta: - id: req_df18014ed48f4e128fea048bb97d77e3 - created: 1776615524600 - modified: 1776615524600 - isPrivate: false - description: "" - sortKey: -1776615518702 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_id - value: account-console - disabled: false - - name: client_secret - value: fae6f87e-5b66-435c-b5aa-fd42c7641604 - disabled: false - - name: grant_type - value: client_credentials - disabled: false - headers: - - name: Content-TypeCo - value: application/jsonapplication/x-www-form-urlencoded - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev/auth/realms/opex/protocol/openid-connect/token - name: Get Access Token for user (expired) - meta: - id: req_0b5f179099c2439c95d62728f4ada79c - created: 1776615524601 - modified: 1776615524601 - isPrivate: false - description: "" - sortKey: -1776615518701 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_id - value: admin-cli - disabled: false - - name: username - value: opex1 - disabled: false - - name: password - value: "123456" - disabled: false - - name: grant_type - value: password - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev/auth/admin/realms/opex/users - name: Create User - meta: - id: req_ff8cabe65c0048358625834a5e511d42 - created: 1776615524602 - modified: 1776615524602 - isPrivate: false - description: "" - sortKey: -1776615518700 - method: POST - body: - mimeType: text/plain - text: "{\r - - \ \t\"createdTimestamp\": 1588880747548,\r - - \ \t\"username\": \"hossein2\",\r - - \ \t\"enabled\": true,\r - - \ \t\"totp\": false,\r - - \ \t\"emailVerified\": true,\r - - \ \t\"firstName\": \"Hossein\",\r - - \ \t\"lastName\": \"Abolhasani\",\r - - \ \t\"email\": \"hossein2@nilin.co\",\r - - \ \t\"disableableCredentialTypes\": [],\r - - \ \t\"requiredActions\": [],\r - - \ \t\"notBefore\": 0,\r - - \ \t\"access\": {\r - - \ \t\"manageGroupMembership\": true,\r - - \ \t\"view\": true,\r - - \ \t\"mapRoles\": true,\r - - \ \t\"impersonate\": true,\r - - \ \t\"manage\": true\r - - \ \t},\r - - \ \t\"realmRoles\": [ \"mb-user\" ]\r - - \t}\r\n" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjQxNzg4NDgsImlhdCI6MTYyNDE3ODU0OCwianRpIjoiZDhjYTJkZDItYWQ3ZS00MDdlLWJmNGMtMGQwMTYyZWI2YTMxIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7InJlYWxtLW1hbmFnZW1lbnQiOnsicm9sZXMiOlsibWFuYWdlLXVzZXJzIl19LCJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiXX19LCJzY29wZSI6InRydXN0IHByb2ZpbGUgZW1haWwiLCJjbGllbnRJZCI6ImFjY291bnQtY29uc29sZSIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xNiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LWFjY291bnQtY29uc29sZSIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xNiJ9.F3MkEklXf3lWDXijIHL0IQ2-tRZCWrLnF0yl5eh2jC1ur7qq70oz_q71N7qAiM7vjtzz4ByYS93JVqd98Ixsuvaa85SthWwOTxcpJNEz3LnD5catNMKAvBZUN1P0WTPzwmfAZQqoEnbiJ7pDSCa0rOltDf5k-B1ksnknjZOw2RHEuIusuOOs9qdtllbJpTFukWWa6LCR1yLSCQOeWByO_xz5cZ9GGgllIgqIPCrOFZY6M913K4w5GaSJQPCLGUyMUFIPyEUdEj4Eis0zjV-8JEH6b-Z7PjjfHUPFGjQ5vSqxPTzjQAKkqxaGdl1UwBNMHNPLcvSeNO4DuHlNgcPqOg - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev/auth/admin/realms/mixchange/users/478cf5d5-5922-413a-b9cb-74e3a860afec/send-verify-email - name: Send Verify Email email - meta: - id: req_b1e4b306455d4344b94515f9272ab0c1 - created: 1776615524603 - modified: 1776615524603 - isPrivate: false - description: |- - User_id : get from Get User Endpoint - - Token : get from Get Access Token for Client - sortKey: -1776615518699 - method: PUT - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjcyOTI3NDQsImlhdCI6MTYyNzI5MjQ0NCwianRpIjoiMzU1NTAwZjgtNDMxOC00NDJlLThlYmYtYmU2ZWQxNzExNzNjIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9vcGV4LmRldiIsImh0dHBzOi8vYXBpLm9wZXguZGV2Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJtYW5hZ2UtdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoiYWNjb3VudC1jb25zb2xlIiwiY2xpZW50SG9zdCI6IjE3Mi4xOC4wLjE4IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtYWNjb3VudC1jb25zb2xlIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjE4In0.sFayDCOv8HFVlDwhX9iWoTfBcTeT3bo7SzEbA_xoexMCqnH6-tmFV98ShfPNh6l5olVwH-_m23f2ghy21NadKgYNklk1Z-oDLs905c0CfI5bR6z1RJSljTOBvfU3hwXZImvBJSKVO3Ut52kgv_ETE10Y_FtxsOMs1PUbFd_AXbFGhN2nzLzg-7_0FiQwQvNmj1jtFGKeHJfIcpsnVQ5QF8VxUgee1cIFvXH3tZvnFvTL66EhV6_6nMGZGV4ql1J5IoYwp5LNh2BqstZp1YWk_prAQM5tt-adX4GHSA1UFUQnyEfpd6qGOGhyCEaTP8S0_s57YrFhiZO86NRKXMKk3A - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev/auth/admin/realms/mixchange/users/5837ff71-129b-44ef-a1af-9bd6378f9e37/execute-actions-email - name: Send Reset password - meta: - id: req_4a1aa9a071e34fc8b951e6b12b85b5ca - created: 1776615524604 - modified: 1776615524604 - isPrivate: false - description: |- - User_id : get from Get User Endpoint - - Token : get from Get Access Token for Client - sortKey: -1776615518698 - method: PUT - body: - mimeType: text/plain - text: '["UPDATE_PASSWORD"]' - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjczMDYxNzMsImlhdCI6MTYyNzMwNTg3MywianRpIjoiYmVhMmZkNDgtMWIzZS00YTc3LTgzODAtMWYzNDgzNTBkYWYzIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9vcGV4LmRldiIsImh0dHBzOi8vYXBpLm9wZXguZGV2IiwiaHR0cDovL2xvY2FsaG9zdDozMDAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJtYW5hZ2UtdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoiYWNjb3VudC1jb25zb2xlIiwiY2xpZW50SG9zdCI6IjE3Mi4xOC4wLjE4IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtYWNjb3VudC1jb25zb2xlIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjE4In0.VFMkDZXbvLyrEbKVnRuxx1oQu7qz8sE8_1h4LvDmegCOJ5_nZwTdybeb5N1QAk96P-H9uFXgU0wCf4M8YDhMl1dKnyculixAMJZJgqROTjsgikVhYcWVn7a3uHKGik1XPt5vDJ4IxzcwnNDrY--cJKQHGAOHdC9kKO6X9F5HmR8ypWjYb8PUQrJSBioNSZcGjLnxZM3EHWq4vnlRp4tBn1v40oUG15HC-OM7yIjlFDnXxzeq3RnXXurQmY7JUX8gUhXRC721pfiTj0iSlGpnPhMx_f0nT-xsckNtk-bWn7S98WFgQYXKnPjnjVe-TRfN5hi2JlTTiccIyujworyYUw - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev/auth/admin/realms/mixchange/users - name: Get User - meta: - id: req_81dbd4aa33a1424997884d320f91cdd6 - created: 1776615524604 - modified: 1776615524604 - isPrivate: false - description: "" - sortKey: -1776615518697 - method: GET - parameters: - - name: username - value: maryam - disabled: false - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlUktVWG10TFhKMHBBNkxBS29aWko1ZlU0VDhCdmxKdERCb3pXanFFdnhjIn0.eyJleHAiOjE2MjcyOTEwNjksImlhdCI6MTYyNzI5MDc2OSwianRpIjoiYWIxZTVlNjctNjQ1NC00OTE0LWFkOWQtZDkxYzA5NzZkNmZkIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvbWl4Y2hhbmdlIiwiYXVkIjpbInJlYWxtLW1hbmFnZW1lbnQiLCJhY2NvdW50Il0sInN1YiI6ImNiNmFmNzU5LTVlNGYtNDJiMy04NmVhLWIzNzU0Y2U0ZDQyMiIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFjY291bnQtY29uc29sZSIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cHM6Ly9vcGV4LmRldiIsImh0dHBzOi8vYXBpLm9wZXguZGV2Il0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsicmVhbG0tbWFuYWdlbWVudCI6eyJyb2xlcyI6WyJtYW5hZ2UtdXNlcnMiXX0sImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudElkIjoiYWNjb3VudC1jb25zb2xlIiwiY2xpZW50SG9zdCI6IjE3Mi4xOC4wLjE4IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtYWNjb3VudC1jb25zb2xlIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjE4In0.CIMkiCIRKBQXCKb4-IuCGKLhDfEkMVwSPHreZcusXjgAe1Su8ENmWgNvTNtDqzgVYCEz74R_fHbihACT8F_sCdN7oK1lP-gWaQuqFRpnaNBclufne-uQtQtdJdF9JMppIpNU7PKy0QBXh4Oz2_GHRBuaHJQSJbja3ZIqm9P-wsBFcY6LXXQagqHtloohgphQ3UhAIWdqICmOhC9QvTdbcvCX0kGZrQRMw8FXsMm26Y652j7jMGJTtfaU4IJ2RB0AlbVYLDbDCh5Y0LGJULt46C7eiV17pbGBihcqXVl92eidt4znORmDhdNdag47aEEqPRLeq0rV0AmhIjgoSI9P0A - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: API Key - meta: - id: fld_64e4017b2aa9441cac0fd8ab9cc52339 - created: 1776615524605 - modified: 1776615524605 - sortKey: -1776615518696 - description: "" - children: - - url: "{{_['api-host']}}/v1/api-key" - name: Get API Key List - meta: - id: req_66884d9810f147d390e1eddff947b718 - created: 1776615524606 - modified: 1776615524606 - isPrivate: false - description: "" - sortKey: -1776615518695 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/api-key" - name: Create API Key - meta: - id: req_a0ac499f74bf43cf9f0ba0e0c2c75bb2 - created: 1776615524607 - modified: 1776615524607 - isPrivate: false - description: "" - sortKey: -1776615518694 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"label\":\"my api key 2\", \r - - \ \"expiration\":\"ONE_MONTH\", // optional - [ONE_MONTH, - THREE_MONTHS, SIX_MONTHS, ONE_YEAR]\r - - \ \"allowedIPs\":\"185.54.69.35,156.255.234.210\" // - optional\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/api-key/a1fb2e91-7cd5-49e2-afad-cf75a726590e/enable" - name: Enable API Key - meta: - id: req_89f34fab6f934048bc1ebd23a9d21d9f - created: 1776615524608 - modified: 1776615524608 - isPrivate: false - description: "" - sortKey: -1776615518693 - method: PUT - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/api-key/a1fb2e91-7cd5-49e2-afad-cf75a726590e" - name: Delete API Key - meta: - id: req_2877bfab133e40d09d9ffab7bd5a5b4d - created: 1776615524609 - modified: 1776615524609 - isPrivate: false - description: "" - sortKey: -1776615518691 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/api-key/a1fb2e91-7cd5-49e2-afad-cf75a726590e/disable" - name: Disable API Key - meta: - id: req_3bbd3e79d64f490abb64bde5ed3545d2 - created: 1776615524609 - modified: 1776615524609 - isPrivate: false - description: "" - sortKey: -1776615518692 - method: PUT - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Auth (new) - meta: - id: fld_19acd55699594749b15533d4f070f6e7 - created: 1776615524614 - modified: 1776615524614 - sortKey: -1776615518687 - description: "" - children: - - url: "{{_['v2auth-host']}}/v1/user/public/register" - name: Request register - meta: - id: req_c961989a6791465dace6d0a5ef5a1a87 - created: 1776615524615 - modified: 1778083333128 - isPrivate: false - description: "" - sortKey: -1776615518686 - method: POST - body: - mimeType: application/json - text: |- - { - "username": "09212880961", // use mobile OR email - "firstName": "Amir", - "lastName": "Rajabi", - "captchaCode" : "1" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/public/register/verify" - name: Verify register - meta: - id: req_84eec8dde7c945f192a9f753b132e394 - created: 1776615524616 - modified: 1776615524616 - isPrivate: false - description: "" - sortKey: -1776615518685 - method: POST - body: - mimeType: application/json - text: |- - { - "username": "hi@opex.dev", - "otp": "48278044" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/public/register/confirm" - name: Confirm register - meta: - id: req_50b17e2234714866b99f33af7b43009b - created: 1776615524617 - modified: 1776615524617 - isPrivate: false - description: "" - sortKey: -1776615518684 - method: POST - body: - mimeType: application/json - text: >- - { - "password": "12345678", - "clientId": "web-app", - "clientSecret": "R9r4amsuwruXacttDwRQBwTS3mEB3FGM", - "rememberMe": true, - "token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvcGV4LWF1dGgiLCJ1c2VySWQiOiJhbWlyQG9wZXguZGV2IiwiYWN0aW9uIjoiUkVHSVNURVIiLCJpYXQiOjE3NTI5MjY3ODUsImV4cCI6MTc1MjkyNjkwNX0.Pv7dkRFYKLgG1QIlcN-6n7sdcliGHEl3wR7B3fDnwalQxjhFLAbIP7qJRtJMjBscSSqJra2MnAxjxeTD527f3n8w8Afa6rm1QGrVpVLTTyIj_6_wmmEKkUquxVQfrjsFdQuf4o0d3H3Yhr2btUPe6Ugn_qDmVCiNk-sjMaogsxr7tXdV9_7x7mXZMd7FSYXT7uwtGU9Vn1ywt1GRy_XaPYVJJE6ifTCBK7GO_atkBkXgFmk9V2rSn7h3E4wQySYj8i2YPUC8r_Is84UTVryzKt-XOP6Veih_uys8Q2INW24CmCm_aiGjyNy3uUiDGMSxsLYfQFap60piX6uJS5Lvrg" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" - name: Request login (otp required) - meta: - id: req_87359bd6a4a14f6baa34139436a3979f - created: 1776615524617 - modified: 1776615524617 - isPrivate: false - description: "" - sortKey: -1776615518683 - method: POST - body: - mimeType: application/json - text: >- - { - "username": "09336461763", // use mobile OR email for username - "password": "12345678", - "clientId": "web-app", - "clientSecret": "4GNyfRVqy7YLBjnWUZWprYfvPQT3sZbQ", - "rememberMe": true, - // "captchaType" :"INTERNAL" optional (default = INTERNAL ) {INTERNAL , ARCHAPTCHA , HCAPTCHA} - "captchaCode" :"edcd2" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" - name: Request login (super-admin) (otp required) - meta: - id: req_48778e02f8314d6a9f2855e9e2c19322 - created: 1776615524618 - modified: 1776615524618 - isPrivate: false - description: "" - sortKey: -1776615518682 - method: POST - body: - mimeType: application/json - text: >- - { - "username": "{{_['super-admin-username']}}", // use mobile OR email for username - "password": "{{_['super-admin-password']}}", - "clientId": "web-app", - "clientSecret": "iXGYTDsCgY6lhaOFJE8GwpUpc5HQ95Wl", - "rememberMe": true, - // "captchaType" :"INTERNAL" optional (default = INTERNAL ) {INTERNAL , ARCHAPTCHA , HCAPTCHA} - "captchaCode" :"edcd2" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" - name: Login (otp required) - meta: - id: req_c215589715bd48d2ad6c02e4f3a53957 - created: 1776615524619 - modified: 1776615524619 - isPrivate: false - description: "" - sortKey: -1776615518681 - method: POST - body: - mimeType: application/json - text: >- - { - "username": "09905135295", // use mobile OR email for username - "password": "Opex@1234", - "clientId": "web-app", - "captchaCode": "asdfasdf", - "rememberMe": true - } - headers: - - name: Content-Type - value: application/json - scripts: - afterResponse: "let user_token=insomnia.response.json().access_token;\r - - insomnia.environment.set(\"user-token\",user-token);" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token/confirm" - name: Login (otp required) Confirm - meta: - id: req_50ad784d186945d881fcdf55ce55d7af - created: 1776615524620 - modified: 1776615524620 - isPrivate: false - description: "" - sortKey: -1776615518679 - method: POST - body: - mimeType: application/json - text: >- - { - "username": "09905135295", // use mobile OR email for username - "token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1NktVakxFVUFFTEVDQUZwbUtnMEY3emI0TVhWRGdXSlVkUldRNk5nYXlRIn0.eyJleHAiOjE3NjU4MTM5MDYsImlhdCI6MTc2NTgxMzc4NiwianRpIjoiZTFlOTk4M2ItZDYwYi00YjkyLWIxZDctOTdjOTYyMjQ5ZDQxIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwcmUtYXV0aC1jbGllbnQiLCJzaWQiOiIxMTczOTcwMy1lMDBkLTRkZGItYTJjMS0xMGE5ZTcyMmI1MzQiLCJzY29wZSI6IiJ9.K3162xOskqrR_ODW5NT5ZRTjZlkc9EREZ4mOuPgn0lj4XqLcvoo2fOEAlG5YTswWXro6LDsDpvPsleAwsoDSCZjtscvykc9_auRChOcMNdx-LXwazdKHvfh-8g0qaPJEqphk6H2YDPul58kpK5BYrwp9zeJ7ZnEjESinDGJBlkAEReSgU2RPXJrphy2sMX5qHHPLR71fgX9IZBY14UF4_ty2FNFacL2H6rX9QADpeSow447tva6zRBnBxitC3Kt1oVzTJ4b9I4EVnNDWE1jVr4Ks2tGbqFr09DXgcWfxi5JvxBQpRfPCs1C9FPAop6rnmNOHplGEyH4QBcrQNlhvew", - "clientId": "web-app", - "otp": "598757", - "rememberMe": true - } - headers: - - name: Content-Type - value: application/json - scripts: - afterResponse: "let user_token=insomnia.response.json().access_token;\r - - insomnia.environment.set(\"user-token\",user-token);" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token/resend-otp" - name: resend otp - meta: - id: req_6c59db28182e40ac9cff8476817756b0 - created: 1776615524620 - modified: 1776615524620 - isPrivate: false - description: "" - sortKey: -1776615518680 - method: POST - body: - mimeType: application/json - text: |- - { - "username": "09905135295", - "clientId":"" - - } - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - scripts: - afterResponse: "let user_token=insomnia.response.json().access_token;\r - - insomnia.environment.set(\"user-token\",user-token);" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" - name: Login (no otp) - meta: - id: req_8d6fa0dff9b14e4b8bc516c2cff637cf - created: 1776615524621 - modified: 1778084439929 - isPrivate: false - description: "" - sortKey: -1776615518678 - method: POST - body: - mimeType: application/json - text: |- - { - "username": "admin@opex.dev", - "password": "Opex@1234", - "clientId": "web-app", - "rememberMe": false, - "captchaCode": "aaa" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" - name: Login (super-admin) - meta: - id: req_cc83a683459045c2a8a5fc344f8928f8 - created: 1776615524622 - modified: 1776615524622 - isPrivate: false - description: "" - sortKey: -1776615518677 - method: POST - body: - mimeType: application/json - text: >- - { - "username": "{{_['super-admin-username']}}", // use mobile OR email for username - "password": "{{_['super-admin-password']}}", - "clientId": "web-app", - "clientSecret": "4GNyfRVqy7YLBjnWUZWprYfvPQT3sZbQ", - "captchaCode": "aaa", - "rememberMe": false, - "token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NjY5NDQzMzYsImlhdCI6MTc2Njk0NDIxNiwianRpIjoiOWU5MTc3YmQtNzFkNS00MWNiLTkwYTMtMmE0YmNmOWU0MWI1IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsicHJlLWF1dGgtY2xpZW50IiwiYWNjb3VudCJdLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwcmUtYXV0aC1jbGllbnQiLCJzaWQiOiJhMGVmNTUyYy0yNmE3LTQxNDgtOWRmOC0xNzNkYTY3MDZlZjgiLCJzY29wZSI6IiJ9.dy5FlJiVOXccxCbF2pZcGc_tm5n-DlwkFfCpeSEiQf2xeb54Zs4FmOa8odCbhDnILwnDrfhjYZl-VOH6kycsd2JN6B82OtXaadksURu8Za6Xr3KMXBtxEjjTOEzM_co-TBttSeM_QM0E_X94MWccUc9cmheRy_P9Y__qe7x5Fcgo4jJz0qSD5B-TJD4VZSJJud2UPHMLOfqzPg3n16Wa7cbatuebJOxCRQGBM5r1bqfOq745SZXhDWbCmGcMFY2AIn3JowDvzGivHLN-4wN341r-YTLmFwPvCmMD47-nKVWqsQOU2-k_0kikFpThaxNp-NZzjXYHbwLKOvBJX93pGA", - "otp": 742560 - } - headers: - - name: Content-Type - value: application/json - scripts: - afterResponse: >- - let - super_admin_token=insomnia.response.json().token.access_token; - - insomnia.environment.set("super-admin-token",super_admin_token); - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/token" - name: Login (super-admin) otp-required confirm - meta: - id: req_0f617db070134287bbbc25ba2825d8c2 - created: 1776615524623 - modified: 1776615524623 - isPrivate: false - description: "" - sortKey: -1776615518676 - method: POST - body: - mimeType: application/json - text: >- - { - "username": "{{_['super-admin-username']}}", // use mobile OR email for username - "password": "{{_['super-admin-password']}}", - "clientId": "web-app", - "clientSecret": "4GNyfRVqy7YLBjnWUZWprYfvPQT3sZbQ", - "captchaCode": "aaa", - "rememberMe": false, - "token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NjY5NDQzMzYsImlhdCI6MTc2Njk0NDIxNiwianRpIjoiOWU5MTc3YmQtNzFkNS00MWNiLTkwYTMtMmE0YmNmOWU0MWI1IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsicHJlLWF1dGgtY2xpZW50IiwiYWNjb3VudCJdLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwcmUtYXV0aC1jbGllbnQiLCJzaWQiOiJhMGVmNTUyYy0yNmE3LTQxNDgtOWRmOC0xNzNkYTY3MDZlZjgiLCJzY29wZSI6IiJ9.dy5FlJiVOXccxCbF2pZcGc_tm5n-DlwkFfCpeSEiQf2xeb54Zs4FmOa8odCbhDnILwnDrfhjYZl-VOH6kycsd2JN6B82OtXaadksURu8Za6Xr3KMXBtxEjjTOEzM_co-TBttSeM_QM0E_X94MWccUc9cmheRy_P9Y__qe7x5Fcgo4jJz0qSD5B-TJD4VZSJJud2UPHMLOfqzPg3n16Wa7cbatuebJOxCRQGBM5r1bqfOq745SZXhDWbCmGcMFY2AIn3JowDvzGivHLN-4wN341r-YTLmFwPvCmMD47-nKVWqsQOU2-k_0kikFpThaxNp-NZzjXYHbwLKOvBJX93pGA", - "otp": 742560 - } - headers: - - name: Content-Type - value: application/json - scripts: - afterResponse: >- - let - super_admin_token=insomnia.response.json().token.access_token; - - insomnia.environment.set("super-admin-token",super_admin_token); - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/oauth/protocol/openid-connect/refresh" - name: Refresh token - meta: - id: req_4ca3ae7053784e94a1b14307921dad52 - created: 1776615524624 - modified: 1776615524624 - isPrivate: false - description: "" - sortKey: -1776615518675 - method: POST - body: - mimeType: application/json - text: >- - { - "clientId": "web-app", - "clientSecret": "iXGYTDsCgY6lhaOFJE8GwpUpc5HQ95Wl", - "refreshToken": "eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjNzIxNTM2OS1hOTlmLTQ0ZDAtYmIxMC1iNzY2MDkyNTUyODYifQ.eyJleHAiOjE3NDcwNTA4MTYsImlhdCI6MTc0NTg0MTIxNiwianRpIjoiYjJmODYwYzAtZGFjMC00M2JlLWFjNzMtZTVhOGZjMmE5ZGJkIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJodHRwOi8va2V5Y2xvYWs6ODA4MC9yZWFsbXMvb3BleCIsInN1YiI6IjE0MmIyNTMwLTI4YjUtNDA2NC05ZWEyLWY5YzRjNWE3NjQ5MyIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiMTAyZWNiNzktZDk5MS00MWM2LTg0ZDctOWQ1M2JkMDgxMTQ2Iiwic2NvcGUiOiJiYXNpYyByb2xlcyBhY3IgdHJ1c3QgcHJvZmlsZSBlbWFpbCB3ZWItb3JpZ2lucyJ9.uRWwoVHmD9KG2hCtNpL-KbE-kU3OXjCBhXg-ljjbV-wVyAXHB1a0IhaxPV36sNHjTHmccYa7s1oQXaTL7gRQ7Q" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/logout" - name: Logout - meta: - id: req_8c623db26c06403fbca86df8770477fc - created: 1776615524625 - modified: 1776615524625 - isPrivate: false - description: "" - sortKey: -1776615518674 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/public/forget" - name: Request forget - meta: - id: req_bd89c659d6354ac38c55f5b9b9d2dbae - created: 1776615524625 - modified: 1776615524625 - isPrivate: false - description: "" - sortKey: -1776615518673 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"username\" :\"hi@gmail.com\",\r - - \ // \"captchaType\" :\"INTERNAL\" optional (default = - INTERNAL ) {INTERNAL , ARCHAPTCHA , HCAPTCHA}\r - - \ \"captchaCode\" :\"edcd2\"\r - - }" - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/public/forget/verify" - name: Verify forget - meta: - id: req_a8d41f04010a4bbf83cb26d244ecd363 - created: 1776615524626 - modified: 1776615524626 - isPrivate: false - description: "" - sortKey: -1776615518672 - method: POST - body: - mimeType: application/json - text: |- - { - "username": "hi@gmail.com", - "otp": "xPFSWwEU" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/public/forget/confirm" - name: Confirm forget - meta: - id: req_495ecfb6e2974edea4589bb961cd768b - created: 1776615524627 - modified: 1776615524627 - isPrivate: false - description: "" - sortKey: -1776615518671 - method: POST - body: - mimeType: application/json - text: >- - { - "newPassword": "22222222", - "newPasswordConfirmation": "22222222", - "token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvcGV4LWF1dGgiLCJ1c2VySWQiOiJoaUBnbWFpbC5jb20iLCJhY3Rpb24iOiJGT1JHRVQiLCJpYXQiOjE3NDY5NjgzOTksImV4cCI6MTc0Njk2ODUxOX0.D_C00eBpWkqH2KIYgXKjlp1PMRW6uyCkcUHlCtGjfZxOG51k2d_4HSJDzThVgaHY1KZsj15ExCX3U1Vxi4OCtG1_oh_g5MH7J3suxcRS5MMv-VONDwekrgCmL0aUHiqg7pu6GlYRBsL8lSIuVJF6g4M6MQUCXerKFAxzaiDiJ9fjl2a9tENw2il9OY68GsHoGajju0iA8UIHeRLZq5B--LjtI9K6e8Aj0UWHv9Tw6d3ikGncwEefA12iL-ZVnnxso3Mq87fte--J6B-dcFlY6o2NzanT6ve5PHGkjt6RPsw_DEGrSoOXnm4Ot_f0tmfWsB8xKKCt0TZgP3qL6ZTbDA" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/session" - name: Active sessions - meta: - id: req_f13952ee397f48deb0a4c297348b00dc - created: 1776615524627 - modified: 1776615524627 - isPrivate: false - description: "" - sortKey: -1776615518670 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/session/e79dc8df-05be-494a-9441-e84108f564d9" - name: Delete one sessions - meta: - id: req_039141c92ecc4774bdd42fc5cd017d38 - created: 1776615524628 - modified: 1776615524628 - isPrivate: false - description: "" - sortKey: -1776615518669 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/session/delete-others" - name: Delete other sessions - meta: - id: req_cd0b6593c83a47e48993a59fb4560865 - created: 1776615524629 - modified: 1776615524629 - isPrivate: false - description: "" - sortKey: -1776615518668 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/session/delete-all" - name: Delete all sessions - meta: - id: req_8af92ab15e1849bcb440ee5475015b64 - created: 1776615524630 - modified: 1776615524630 - isPrivate: false - description: "" - sortKey: -1776615518667 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['v2auth-host']}}/v1/user/session" - name: Sessions - meta: - id: req_2855e1e36ee04cedb5c7d6841542e1d6 - created: 1776615524631 - modified: 1776615524631 - isPrivate: false - description: "" - sortKey: -1776615518666 - method: POST - body: - mimeType: application/json - text: >- - { - - "limit": 10, - "offset": 0, - "ascendingByTime": false, - "os": "ANDROID", //nul, ANDROID, IOS, MOBILE_WEB, DESKTOP_WEB - "status": "ACTIVE"// ACTIVE, EXPIRED, TERMINATED - } - headers: - - name: Accept-Language - value: EN - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Wallet - meta: - id: fld_1b63e4888c724c699368c73b7a819c3e - created: 1776615524632 - modified: 1776615524632 - sortKey: -1776615518665 - description: "" - children: - - url: "{{_['api-host']}}/v3/account" - name: Account Info - meta: - id: req_55e99e558fb945a48238ccbfd917f8e7 - created: 1776615524645 - modified: 1776615524645 - isPrivate: false - description: "" - sortKey: -1776615518649 - method: GET - parameters: - - name: timestamp - value: "1626805452" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{host}}/sapi/v1/capital/deposit/address" - name: Address - meta: - id: req_cab2137066cc49a8a430c9f1e779ec99 - created: 1776615524645 - modified: 1776615524645 - isPrivate: false - description: "" - sortKey: -1776615518648 - method: GET - parameters: - - name: coin - value: TUSDT - disabled: false - - name: timestamp - value: "1" - disabled: false - - name: network - value: test-tron - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/balanceOf/wallet_type/main/currency/usdt" - name: Balance Of - meta: - id: req_3c5422fbdf724cea8146e85608e2b81b - created: 1776615524647 - modified: 1776615524647 - isPrivate: false - description: "" - sortKey: -1776615518647 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{host}}/sapi/v1/capital/withdraw/history" - name: Withdraw - meta: - id: req_bbd3bbd0aca94e108258b1a9ef69e893 - created: 1776615524647 - modified: 1776615524647 - isPrivate: false - description: "" - sortKey: -1776615518646 - method: GET - parameters: - - name: coin - value: eth - disabled: false - - name: timestamp - value: "1" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/transaction/86e471f8-c818-4b9a-9198-23f269c9cb9e" - name: Transaction History - meta: - id: req_10683ed1a5c4400d8d97ed66012c4b4e - created: 1776615524648 - modified: 1776615524648 - isPrivate: false - description: "" - sortKey: -1776615518645 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"coin\": \"BTC\", // optional\r - - \ \"category\": \"DEPOSIT\", // optional [DEPOSIT, FEE, - TRADE, WITHDRAW, ORDER_CANCEL, ORDER_CREATE, ORDER_FINALIZED]\r - - \ \"startTime\": 1662190330000,\r - - \ \"endTime\": 1693828960000,\r - - \ \"limit\": 10,\r - - \ \"offset\": 0\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/v1/deposit/manually/20_USDT/dcb7c726-8e0e-40ba-a8c7-\ - 5a017905176d" - name: Deposit Manually - meta: - id: req_870e61c294a040308c6852c6bb996325 - created: 1776615524649 - modified: 1776615524649 - isPrivate: false - description: "" - sortKey: -1776615518644 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"description\":\"Sign up gift\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{host}}/sapi/v1/capital/deposit/hisrec" - name: Deposit - meta: - id: req_f27e0ce346c2493f8e3948a6800b9549 - created: 1776615524650 - modified: 1776615524650 - isPrivate: false - description: "" - sortKey: -1776615518643 - method: GET - parameters: - - name: coin - value: eth - disabled: false - - name: timestamp - value: "1" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: stats - meta: - id: fld_e5abe1a673bb4d8ca0e6b8aa322bdd17 - created: 1776615524633 - modified: 1776615524633 - sortKey: -1776615518664 - description: "" - children: - - url: "{{_['wallet-host']}}/stats/wallets" - name: Wallet Data - meta: - id: req_ed14cf56e952499d93b73ded60a3fbed - created: 1776615524633 - modified: 1776615524633 - isPrivate: false - description: "" - sortKey: -1776615518663 - method: GET - parameters: - - name: uuid - value: b15b185b-5b4c-4cca-beea-d449e1503bc1 - disabled: false - - name: walletType - value: MAIN - disabled: false - - name: currency - value: TUSDT - disabled: false - - name: excludeSystem - value: "true" - disabled: false - - name: limit - value: "100" - disabled: false - - name: offset - value: "0" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/stats/wallets/system/total" - name: Wallet Total System - meta: - id: req_5e234211b97f4f87a102556e8ae41266 - created: 1776615524634 - modified: 1776615524634 - isPrivate: false - description: "" - sortKey: -1776615518662 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/stats/wallets/user/total" - name: Wallet Total Users - meta: - id: req_7447cf97c0c8499da0b75df034456bce - created: 1776615524635 - modified: 1776615524635 - isPrivate: false - description: "" - sortKey: -1776615518661 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/stats/v2/wallets" - name: Wallet Data V2 - meta: - id: req_8e67204e187c4d73b896548639f91004 - created: 1776615524636 - modified: 1776615524636 - isPrivate: false - description: "" - sortKey: -1776615518660 - method: GET - parameters: - - name: uuid - value: 29599226-61e3-41fd-9f2d-c801b78f9400 - disabled: false - - name: currency - value: USDT - disabled: false - - name: excludeSystem - value: "true" - disabled: false - - name: limit - value: "10" - disabled: false - - name: offset - value: "0" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Withdraw - meta: - id: fld_036ed18225b44cc6a6ece9b3272b2482 - created: 1776615524637 - modified: 1776615524637 - sortKey: -1776615518659 - description: "" - children: - - url: "{{_['wallet-host']}}/withdraw" - name: Request withdraw - meta: - id: req_4753671c2938421c83184f28a01f4840 - created: 1776615524637 - modified: 1776615524637 - isPrivate: false - description: "" - sortKey: -1776615518658 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"currency\": \"USDT\",\r - - \ \"gatewayUuid\":\"121\"\r - - \ \"amount\": 1,\r - - \ \"destAddress\": - \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r - - \ \"destNetwork\": \"test-ethereum\",\r - - \ \"destNote\": \"Personal wallet\", //Optional\r - - \ \"description\": \"Withdrawal to personal wallet\" - //Optional\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/withdraw/1" - name: Get withdraw - meta: - id: req_b768c0d24c4b4cb68103c9157c096d9a - created: 1776615524638 - modified: 1776615524638 - isPrivate: false - description: "" - sortKey: -1776615518657 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/withdraw/search" - name: Search withdraw - meta: - id: req_e839064155a8437fae8feaaa3e66f485 - created: 1776615524639 - modified: 1776615524639 - isPrivate: false - description: "" - sortKey: -1776615518656 - method: POST - body: - mimeType: application/json - text: "{ //All fields are optional\r - - \ \"currency\": \"BTC\",\r - - \ \"destTxRef\": \"tx123456789\",\r - - \ \"destAddress\": - \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r - - \ \"status\": [\"CREATED\", \"PROCESSING\", \"CANCELED\", - \"REJECTED\", \"DONE\"]\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/withdraw/3/cancel" - name: Cancel withdraw - meta: - id: req_7d7e415b0eaa48a2884376b3f4477a52 - created: 1776615524640 - modified: 1776615524640 - isPrivate: false - description: "" - sortKey: -1776615518655 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/withdraw/search" - name: Admin search - meta: - id: req_3723e999d66a40cdbbb3fe04abc889ae - created: 1776615524641 - modified: 1776615524641 - isPrivate: false - description: "" - sortKey: -1776615518653 - method: POST - body: - mimeType: application/json - text: "{ //All fields are optional\r - - \ \"uuid\":\"some uuid\",\r - - \ \"currency\": \"BTC\",\r - - \ \"destTxRef\": \"tx123456789\",\r - - \ \"destAddress\": - \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r - - \ \"status\": [\"CREATED\", \"PROCESSING\", \"CANCELED\", - \"REJECTED\", \"DONE\"]\r - - }" - parameters: - - name: offset - value: "0" - disabled: false - - name: size - value: "10" - disabled: false - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/withdraw/2" - name: Admin get withdraw - meta: - id: req_8d7e0a7c011a475aa2a5341679bc24be - created: 1776615524641 - modified: 1776615524641 - isPrivate: false - description: "" - sortKey: -1776615518654 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/withdraw/2/process" - name: Admin process withdraw - meta: - id: req_cabfa416d86e4d7f8fbb1607499e698e - created: 1776615524642 - modified: 1776615524642 - isPrivate: false - description: "" - sortKey: -1776615518652 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/withdraw/2/reject" - name: Admin reject withdraw - meta: - id: req_d2274f2c2d9646d5a1d92992adc50305 - created: 1776615524643 - modified: 1776615524643 - isPrivate: false - description: "" - sortKey: -1776615518651 - method: POST - parameters: - - name: reason - value: Some reason - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/withdraw/5/accept" - name: Admin accept withdraw - meta: - id: req_e0bc2b56be104d0f85355c54b47fe273 - created: 1776615524644 - modified: 1776615524644 - isPrivate: false - description: "" - sortKey: -1776615518650 - method: POST - parameters: - - name: destTransactionRef - value: 0xsdf3j984fhe89fv834h893h - disabled: false - - name: destNote - value: "" - disabled: true - - name: destAmount - value: "" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Dashboard - meta: - id: fld_b6c1b983970c43d281f78964e601a437 - created: 1776615524650 - modified: 1776615524650 - sortKey: -1776615518642 - description: "" - children: - - url: "{{_['api-host']}}/v1/asset/tradeFee" - name: Fee For Symbol - meta: - id: req_1a17c66d2d914713adab8916fb999835 - created: 1776615524671 - modified: 1776615524671 - isPrivate: false - description: "" - sortKey: -1776615518619 - method: GET - parameters: - - name: symbol - value: TBTCTUSDT - disabled: false - - name: timestamp - value: "1" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['user-token']}}/v1/asset/getUserAsset" - name: User Assets - meta: - id: req_74436edeef5b426ba90777832b5a5b33 - created: 1776615524671 - modified: 1776615524671 - isPrivate: false - description: "" - sortKey: -1776615518618 - method: GET - parameters: - - name: symbol - value: TBTC - disabled: false - - name: quoteAsset - value: USDT - disabled: false - - name: calculateEvaluation - value: "true" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/asset/estimatedValue" - name: User Assets Estimated Value - meta: - id: req_d603aa47b06640bcb11ac7d6034385fd - created: 1776615524672 - modified: 1776615524672 - isPrivate: false - description: "" - sortKey: -1776615518617 - method: GET - parameters: - - name: quoteAsset - value: USDT - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/currencyInfo/quotes" - name: Quote currencies - meta: - id: req_877ecfcce6b14a99abf358a58b61324a - created: 1776615524673 - modified: 1776615524673 - isPrivate: false - description: "" - sortKey: -1776615518616 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/analytics/user-activity" - name: user-activity - meta: - id: req_ee8a355ddd3744e5983bea64063a90f4 - created: 1776615524674 - modified: 1776615524674 - isPrivate: false - description: "" - sortKey: -1776615518615 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Order - meta: - id: fld_372cab9706324ac79872b1a13c79fc0a - created: 1776615524651 - modified: 1776615524651 - sortKey: -1776615518641 - description: "" - children: - - url: "{{_['api-host']}}/v3/order" - name: Create Order - meta: - id: req_cd14c4b949d047b697d5c7c48fbd8051 - created: 1776615524652 - modified: 1776615524652 - isPrivate: false - description: "" - sortKey: -1776615518640 - method: POST - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: side - value: SELL - disabled: false - - name: type - value: LIMIT - disabled: false - - name: timeInForce - value: GTC - disabled: false - - name: timestamp - value: "1626805452" - disabled: false - - name: quantity - value: "0.01" - disabled: false - - name: price - value: "50000" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/order" - name: Cancel Order - meta: - id: req_6531663c67a24123b37063401acd9913 - created: 1776615524653 - modified: 1776615524653 - isPrivate: false - description: "" - sortKey: -1776615518639 - method: DELETE - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: timestamp - value: "1626805452" - disabled: false - - name: orderId - value: "2687" - disabled: false - - name: origClientOrderId - value: "" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Overview - meta: - id: fld_ff7bcad220eb41a092ddd01d32573d54 - created: 1776615524654 - modified: 1776615524654 - sortKey: -1776615518638 - description: "" - children: - - url: "{{_['api-host']}}/v3/ticker/24h" - name: 24h - meta: - id: req_839d4c351efa4012985af9a7a7e42ed1 - created: 1776615524655 - modified: 1776615524655 - isPrivate: false - description: "" - sortKey: -1776615518637 - method: GET - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: quote - value: USDT - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/ticker/24h" - name: 24h Copy - meta: - id: req_9170ee185a3743909afb0d15854eff80 - created: 1776615524656 - modified: 1776615524656 - isPrivate: false - description: "" - sortKey: -1776615518636 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/ticker/7d" - name: 7d - meta: - id: req_fca29198162d425ebc8ceb34a7c2dfd1 - created: 1776615524656 - modified: 1776615524656 - isPrivate: false - description: "" - sortKey: -1776615518635 - method: GET - parameters: - - name: symbol - value: TBTCTUSDT - disabled: false - - name: quote - value: TUSDT - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/ticker/1M" - name: 1m - meta: - id: req_6bd92a94291d48f1953c8d0ff691bcce - created: 1776615524657 - modified: 1776615524657 - isPrivate: false - description: "" - sortKey: -1776615518634 - method: GET - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: quote - value: USDT - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: OrderBook - meta: - id: fld_0878e595828841aab180baaace880b15 - created: 1776615524658 - modified: 1776615524658 - sortKey: -1776615518633 - description: "" - children: - - url: "{{_['api-host']}}/v3/depth" - name: Order Book - meta: - id: req_9813f74f83434a8d82788986121d0f87 - created: 1776615524658 - modified: 1776615524658 - isPrivate: false - description: "" - sortKey: -1776615518632 - method: GET - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: limit - value: "10" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: LastTrades - meta: - id: fld_99c33eb5ad314b5e98acf0eb9b6947c2 - created: 1776615524659 - modified: 1776615524659 - sortKey: -1776615518631 - description: "" - children: - - url: "{{_['api-host']}}/v3/trades" - name: Last Trades - meta: - id: req_f15fe75fe6984bb6bc59beaf9c83996f - created: 1776615524660 - modified: 1776615524660 - isPrivate: false - description: "" - sortKey: -1776615518630 - method: GET - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: limit - value: "100" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: MyOrder - meta: - id: fld_1083f85a1f82454296fb54fffdd371ce - created: 1776615524660 - modified: 1776615524660 - sortKey: -1776615518629 - description: "" - children: - - url: "{{_['api-host']}}/v3/openOrders" - name: All Orders - meta: - id: req_51da5e0273584dad8ee06fd61957bca8 - created: 1776615524661 - modified: 1776615524661 - isPrivate: false - description: "" - sortKey: -1776615518628 - method: GET - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: recvWindow - value: "1" - disabled: false - - name: timestamp - value: "1" - disabled: false - headers: - - name: Accept - value: application/json - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/myTrades" - name: Trades - meta: - id: req_64c393b9061445458af94e9abd2fd340 - created: 1776615524663 - modified: 1776615524663 - isPrivate: false - description: "" - sortKey: -1776615518627 - method: GET - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: startTime - value: "" - disabled: false - - name: endTime - value: "" - disabled: false - - name: timestamp - value: "1" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['user-token']}}/v3/order" - name: Query Order - meta: - id: req_b222f1ab127f4b7285428cd727c12631 - created: 1776615524664 - modified: 1776615524664 - isPrivate: false - description: "" - sortKey: -1776615518626 - method: GET - parameters: - - name: orderId - value: "30" - disabled: false - - name: symbol - value: BTCUSDT - disabled: false - - name: recvWindow - value: "1" - disabled: false - - name: timestamp - value: "1" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/openOrders" - name: Open Orders - meta: - id: req_5b1d36afd0a24b12a7466f897e8be987 - created: 1776615524665 - modified: 1776615524665 - isPrivate: false - description: "" - sortKey: -1776615518625 - method: GET - parameters: - - name: symbol - value: BTCUSDT - disabled: false - - name: recvWindow - value: "1" - disabled: false - - name: timestamp - value: "1" - disabled: false - headers: - - name: Accept - value: application/json - - name: Content-Type - value: application/x-www-form-urlencoded - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Market - meta: - id: fld_736a55d770224fbfa852dd38584951b6 - created: 1776615524665 - modified: 1776615524665 - sortKey: -1776615518624 - description: "" - children: - - url: "{{_['market-host']}}/v1/chart/spark-line" - name: Spark-line - meta: - id: req_cb9399cf31024070916790354d48e836 - created: 1776615524666 - modified: 1776615524666 - isPrivate: false - description: "" - sortKey: -1776615518623 - method: GET - body: - mimeType: application/json - text: "{\r - - \ \"symbols\":[\"BTC_USDT\", \"ETH_USDT\", - \"BTC_USDT\"],\r - - \ \"period\" : \"WEEKLY\"\r - - }" - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/ticker/price" - name: Price - meta: - id: req_4a469796d36841a69e08dd86bc09834c - created: 1776615524667 - modified: 1776615524667 - isPrivate: false - description: "" - sortKey: -1776615518622 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/exchangeInfo" - name: Exchange Info - meta: - id: req_7e4121de7b7f4407aff8713517b09df0 - created: 1776615524668 - modified: 1776615524668 - isPrivate: false - description: "" - sortKey: -1776615518621 - method: GET - parameters: - - name: symbol - value: "" - disabled: false - - name: symbols - value: "" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v3/currencyInfo" - name: Currency Info - meta: - id: req_152384de0ed44dc2b996ea7260da06f7 - created: 1776615524670 - modified: 1776615524670 - isPrivate: false - description: "" - sortKey: -1776615518620 - method: GET - parameters: - - name: currency - value: TUSDT - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Admin - meta: - id: fld_2aac192d51ec4128a8e2bc9aeaae4716 - created: 1776615524674 - modified: 1776615524674 - sortKey: -1776615518614 - description: "" - children: - - url: "{{_['auth-host']}}/auth/v1/user/impersonate" - name: Impersonate - meta: - id: req_701a41e6bca543588b007bc863c4ff66 - created: 1776615524675 - modified: 1776615524675 - isPrivate: false - description: "" - sortKey: -1776615518613 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"clientId\":\"web-app\",\r - - \ \"clientSecret\":\"7aba841f-f178-46ba-8b6d-6bd7d432115a\",\ - \r - - \ \"userId\":\"8b1e4016-25cb-4481-a315-2e854ae0f643\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/realms/opex/protocol/openid-connect/token" - name: Get Access Token - meta: - id: req_7c1ce81e2865453aae86ec222f1f4ea1 - created: 1776615524676 - modified: 1776615524676 - isPrivate: false - description: "" - sortKey: -1776615518612 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: client_id - value: web-app - disabled: false - - name: username - value: "{{_['admin-username']}}" - disabled: false - - name: password - value: "{{_['admin-password']}}" - disabled: false - - name: grant_type - value: password - disabled: false - - name: client_secret - value: "{{_['web-app-secret']}}" - disabled: false - - name: agent - value: postman - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/v1/user/0d510617-5505-4ed6-b6b8-b1df5a4ff784" - name: User Details - meta: - id: req_1bbd2f3b03ae4d0dab95e3e8bd30bb2d - created: 1776615524677 - modified: 1776615524677 - isPrivate: false - description: "" - sortKey: -1776615518611 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/v1/user" - name: List Auth Users - meta: - id: req_74962fa68a634f15b57f2c98e941d3e8 - created: 1776615524678 - modified: 1776615524678 - isPrivate: false - description: "" - sortKey: -1776615518610 - method: GET - parameters: - - name: offset - value: "1" - disabled: false - - name: size - value: "10" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/v1/group/kyc-accepted/members" - name: List Group Members - meta: - id: req_8e5c35cf5dc745a6a91e3b0f9db01d8d - created: 1776615524680 - modified: 1776615524680 - isPrivate: false - description: "" - sortKey: -1776615518609 - method: GET - parameters: - - name: offset - value: "0" - disabled: false - - name: size - value: "10" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['auth-host']}}/auth/v1/user/search" - name: Search Users - meta: - id: req_2f0c27c22792433d8d42d960b80feab4 - created: 1776615524681 - modified: 1776615524681 - isPrivate: false - description: "" - sortKey: -1776615518608 - method: GET - parameters: - - name: offset - value: "0" - disabled: false - - name: size - value: "10" - disabled: false - - name: search - value: demo1 - disabled: false - - name: by - value: email - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-token']}}/auth/v1/user/8b1e4016-25cb-4481-a315-2e854ae0f643/ky\ - c/accept" - name: User Accept KYC - meta: - id: req_65e4a3c3b0984d8bb43275c45cd13f54 - created: 1776615524681 - modified: 1776615524681 - isPrivate: false - description: "" - sortKey: -1776615518607 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-token']}}/auth/v1/user/24ab618d-9eaf-44f3-b506-83422416d4cb/ky\ - c/reject" - name: User Reject KYC - meta: - id: req_7a2a73f8cb7f49298fed23e5354be1c6 - created: 1776615524682 - modified: 1776615524682 - isPrivate: false - description: "" - sortKey: -1776615518606 - method: POST - parameters: - - name: reason - value: عکس ارسال شده با کارت ملی تطابق ندارد. - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-token']}}/auth/v1/user/0ba5fde2-8e93-4f5a-9d8d-ce6057adf2e7/ky\ - c/block" - name: User Block KYC - meta: - id: req_7c090c2be41b47d586e30278e85e2e02 - created: 1776615524683 - modified: 1776615524683 - isPrivate: false - description: "" - sortKey: -1776615518605 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-token']}}/auth/v1/user/8b1e4016-25cb-4481-a315-2e854ae0f643/jo\ - in-kyc" - name: User Join KYC Group - meta: - id: req_15707d5e1eff494a99f1fe9b4c03ecd9 - created: 1776615524685 - modified: 1776615524685 - isPrivate: false - description: "" - sortKey: -1776615518604 - method: POST - parameters: - - name: kycGroup - value: REQUESTED - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-host']}}/system/v1/currency" - name: Add Currency - meta: - id: req_75f0cb31e7c049f6bbe766650ab63e23 - created: 1776615524685 - modified: 1776615524685 - isPrivate: false - description: "" - sortKey: -1776615518603 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"name\":\"Solana\",\r - - \ \"symbol\":\"SOL\",\r - - \ \"precision\": 0.0001\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-host']}}/system/v1/currency/Solana" - name: Edit Currency - meta: - id: req_2d30b9a882244512aeb0a0ebee17913a - created: 1776615524686 - modified: 1776615524686 - isPrivate: false - description: "" - sortKey: -1776615518602 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"symbol\":\"SOLL\",\r - - \ \"precision\": 0.01\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-token']}}/system/v1/currency/Solana" - name: Delete Currency - meta: - id: req_1f35006d273440bebab6fedfabd8b511 - created: 1776615524687 - modified: 1776615524687 - isPrivate: false - description: "" - sortKey: -1776615518601 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/chain - name: Add New Chain - meta: - id: req_0b356d823d8a4d5a8b7218f172ec5ec1 - created: 1776615524688 - modified: 1776615524688 - isPrivate: false - description: "" - sortKey: -1776615518600 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"name\":\"ether-classic\",\r - - \ \"addressType\":\"ethereum\",\r - - \ \"scannerEndpoint\": null,\r - - \ \"scheduleDelaySeconds\": 600,\r - - \ \"scheduleErrorDelaySeconds\": 300\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/address/type - name: Add Address Type - meta: - id: req_3e2821d50a92479498783ea1a958cc9c - created: 1776615524688 - modified: 1776615524688 - isPrivate: false - description: "" - sortKey: -1776615518599 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"name\":\"solana\",\r - - \ \"addressRegex\":\".*\",\r - - \ \"memoRegex\":null\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/token - name: Add New Token - meta: - id: req_a1ff906db8074c89a6253877335b82b3 - created: 1776615524689 - modified: 1776615524689 - isPrivate: false - description: "" - sortKey: -1776615518598 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"symbol\":\"SHIB\",\r - - \ \"chain\":\"ethereum\",\r - - \ \"isToken\": true,\r - - \ \"tokenName\": \"Shiba\",\r - - \ \"tokenAddress\": - \"0x95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce\",\r - - \ \"withdrawFee\":0.1,\r - - \ \"minimumWithdraw\":100000000,\r - - \ \"isWithdrawEnabled\":true,\r - - \ \"decimal\":18\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/address/type - name: Get Address Types - meta: - id: req_2ebe27a597fd4dd2813d9780322f4801 - created: 1776615524690 - modified: 1776615524690 - isPrivate: false - description: "" - sortKey: -1776615518596 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/chain - name: Get Chains - meta: - id: req_a75c250ffc1d421f9e893bf5c01726fe - created: 1776615524690 - modified: 1776615524690 - isPrivate: false - description: "" - sortKey: -1776615518597 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/token - name: Get Tokens - meta: - id: req_59a059ced3194b988581329f0560636b - created: 1776615524691 - modified: 1776615524691 - isPrivate: false - description: "" - sortKey: -1776615518595 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/chain/ethereum-classic/endpoint - name: Set Chain Endpoint - meta: - id: req_b8c7e24c30d44833bd10cb5b05ec711e - created: 1776615524692 - modified: 1776615524692 - isPrivate: false - description: "" - sortKey: -1776615518594 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"url\":\"http://yomamasofat.com\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/chain/ethereum-classic/endpoint - name: Delete Chain Endpoint - meta: - id: req_71a2c9f1111c4867bcfda1a664ed9dfb - created: 1776615524693 - modified: 1776615524693 - isPrivate: false - description: "" - sortKey: -1776615518593 - method: DELETE - parameters: - - name: url - value: http://g.com - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-host']}}/system/v1/whitelist" - name: Get whitelist user - meta: - id: req_4239e4206e5a45e58e60095ee0c9d473 - created: 1776615524694 - modified: 1776615524694 - isPrivate: false - description: "" - sortKey: -1776615518592 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-host']}}/system/v1/whitelist" - name: Update whitelist user - meta: - id: req_4d13b5d67b3746ae8e125bf4aaf2bae6 - created: 1776615524695 - modified: 1776615524695 - isPrivate: false - description: "" - sortKey: -1776615518591 - method: POST - body: - mimeType: application/json - text: '{"data":["sara","sinnba"]}' - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-host']}}/system/v1/whitelist" - name: Delete whitelist user - meta: - id: req_1b65ba10d6944d4e83f50ae4f8e97b91 - created: 1776615524696 - modified: 1776615524696 - isPrivate: false - description: "" - sortKey: -1776615518590 - method: DELETE - body: - mimeType: application/json - text: '{"data":["sara"]}' - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/deposit/manually/0.00001_BTC/7440dffe-8332-477\ - 5-83c2-b5880c526c48" - name: Manual Deposit - meta: - id: req_7501ec53bc744c608813ad1a58816ffd - created: 1776615524697 - modified: 1776615524697 - isPrivate: false - description: "" - sortKey: -1776615518589 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"description\":\"test1\",\r - - \ \"ref\":\"test1\",\r - - \ \"gatewayUuid\":\"mag_f8b26943-4511-422d-8b5a-398b226815a2\ - \"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8095/admin/addresses - name: Add Addresses - meta: - id: req_6f1419e50e654061bcb87d35c40d959e - created: 1776615524698 - modified: 1776615524698 - isPrivate: false - description: "" - sortKey: -1776615518587 - method: POST - body: - mimeType: application/json - text: "// {\r - - // \"addresses\": [\"test1\", \"test2\", \"test3\"],\r - - // \"memos\": [\"memo1\", \"memo2\", null],\r - - // \"addressType\": \"ethereum\"\r - - // }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/deposit/manually/{amount}_{symbol}/{receiverUuid}" - name: Manual Deposit Copy - meta: - id: req_76fc87a7dd5e42fd88fb8f87ea285a4b - created: 1776615524698 - modified: 1776615524698 - isPrivate: false - description: "" - sortKey: -1776615518588 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"description\":\"test\",\r - - \ \"ref\":\"test\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-host']}}/v1/market/recent-trades" - name: Recent Trades - meta: - id: req_44ef6bdae46a493098bc1cf53d048360 - created: 1776615524699 - modified: 1776615524699 - isPrivate: false - description: "" - sortKey: -1776615518586 - method: GET - body: - mimeType: application/json - text: "{\r - - \"symbol\":\"BTC_USDT\",\r - - \"limit\" :10,\r - - \"offset\":0,\r - - // \"takerUuid\" : \"5669d02d-5be8-48a2-a985-67eb33bc309b\"\r - - \"excludeSelfTrade\" : false\r - - // \"makerUuid\" : \"5669d02d-5be8-48a2-a985-67eb33bc309b\"\r - - // \"fromDate\" :11111\r - - // \"toDate\" :11111\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/quotes" - name: Get quote currencies - meta: - id: req_8704beb5154e4847b805eef3e655cc7e - created: 1776615524700 - modified: 1776615524700 - isPrivate: false - description: "" - sortKey: -1776615518585 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/quote/USDT" - name: Update quote currency - meta: - id: req_f4362943a1a9476eb08cef50cd1fd73d - created: 1776615524701 - modified: 1776615524701 - isPrivate: false - description: "" - sortKey: -1776615518584 - method: PUT - parameters: - - name: isActive - value: "true" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/rate-limit" - name: Refresh Rate Limit - meta: - id: req_c9178e0c335c4563aca214e544a64019 - created: 1776615524702 - modified: 1776615524702 - isPrivate: false - description: "" - sortKey: -1776615518583 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Admin (new) - meta: - id: fld_f6933d1c8cff4ecb8817006ea972d6d7 - created: 1776615524702 - modified: 1776615524702 - sortKey: -1776615518582 - description: "" - children: - - name: Profile - meta: - id: fld_fa7b5ac4f18b45459d11c937aea4816e - created: 1776615524703 - modified: 1776615524703 - sortKey: -1776615518581 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/admin/profile/9ba9a448-354d-4c07-a432-1249871c4\ - 5b8" - name: Get Profile - meta: - id: req_1a103e7c6e3c472d813b2ea641345ad1 - created: 1776615524704 - modified: 1776615524704 - isPrivate: false - description: "" - sortKey: -1776615518579 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/profile" - name: Get Profiles - meta: - id: req_a77d5336c896434abb172898b5e09927 - created: 1776615524704 - modified: 1776615524704 - isPrivate: false - description: "" - sortKey: -1776615518580 - method: POST - body: - mimeType: application/json - text: "{\r - - \ //\"userId\": null, // optional\r - - \ //\"firstName\": null, // optional\r - - \ //\"lastName\": null, // optional\r - - \ //\"mobile\": null, // optional\r - - \ //\"email\": null, // optional\r - - \ //\"identifier\": null, // optional\r - - \ //\"nationality\": null, // optional (IRANAIN , - NON_IRANIAN)\r - - \ //\"gender\": null, // optional (FEMALE, MALE)\r - - \ //\"status\": null, // optional - (CREATED,CONTACT_INFO_COMPLETED,PROFILE_COMPLETED,SYSTEM_AP\ - PROVED,PENDING_ADMIN_APPROVAL,ADMIN_REJECTED,ADMIN_APPROVED)\ - \r - - \ //\"kycLevel\": null, // optional ( LEVEL_1, - LEVEL_2, LEVEL_3 )\r - - \ //\"createDateFrom\": null, // optional (timestamp)\r - - \ //\"createDateTo\": null, // optional (timestamp)\r - - \ \"limit\": 10, // (default 10)\r - - \ \"offset\": 0, // (default 0)\r - - \ \"ascendingByTime\": false // (default false)\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/profile/history/ec06fbc0-6041-48e3-b5f6-9\ - cd2ef57edb9" - name: Get Profile History - meta: - id: req_847dcd28bfb247088f1fe2b678f3dff1 - created: 1776615524705 - modified: 1776615524705 - isPrivate: false - description: "" - sortKey: -1776615518578 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/profile/approval-requests" - name: Get Approval Requests - meta: - id: req_20fb64953af84da6bafa6118948886ab - created: 1776615524706 - modified: 1776615524706 - isPrivate: false - description: "" - sortKey: -1776615518577 - method: POST - body: - mimeType: application/json - text: "{\r - - \ //\"userId\": null, // optional\r - - \ //\"status\": null, // optional (PENDING, - APPROVED, REJECTED)\r - - \ //\"createDateFrom\": null, // optional (timestamp)\r - - \ //\"createDateTo\": null, // optional (timestamp)\r - - \ \"limit\": 10, // (default 10)\r - - \ \"offset\": 0, // (default 0)\r - - \ \"ascendingByTime\": false // (default false)\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/profile/approval-request/7" - name: Get Approval Request - meta: - id: req_bac7466c1b4d4cae9b8916f5a5fc3033 - created: 1776615524706 - modified: 1776615524706 - isPrivate: false - description: "" - sortKey: -1776615518576 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/profile/approval-request" - name: Update Approval Request - meta: - id: req_536340206f9f4f15b56a92f54825c7bb - created: 1776615524707 - modified: 1776615524707 - isPrivate: false - description: "" - sortKey: -1776615518575 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"id\": 2,\r - - \ \"description\": \"test\", // optional\r - - \ \"status\": \"REJECTED\" //(APPROVED, REJECTED)\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Transactions - meta: - id: fld_e1dcc1b014e24203a01d8317af8ae26e - created: 1776615524708 - modified: 1776615524708 - sortKey: -1776615518574 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/admin/transactions/summary" - name: Get User Transaction Summary - meta: - id: req_2fac7fc3653e4804a47dca75e15dabc9 - created: 1776615524709 - modified: 1776615524709 - isPrivate: false - description: "" - sortKey: -1776615518573 - method: POST - body: - mimeType: application/json - text: "{\r - - \ //\"userId\": null, // optional\r - - \ //\"currency\": null, // optional\r - - \ //\"sourceSymbol\": null, // optional\r - - \ //\"destSymbol\": null, // optional\r - - \ //\"category\": null, // optional - (TRADE,DEPOSIT,DEPOSIT_TO,WITHDRAW_FROM,WITHDRAW,FEE,SWAP,R\ - EFERRAL_COMMISSION,REFERRAL_KYC_REWARD,REFERENT_COMMISSION,\ - KYC_ACCEPTED_REWARD,SYSTEM)\r - - \ //\"startTime\": null, // optional (timestamp)\r - - \ //\"endTime\": null, // optional (timestamp)\r - - \ \"limit\": 10, // (default 10)\r - - \ \"offset\": 0, // (default 0)\r - - \ \"ascendingByTime\": false // (default false)\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/transactions/deposits" - name: Get Deposit Transactions - meta: - id: req_180b3e07076e4baea88f6d44458be169 - created: 1776615524710 - modified: 1776615524710 - isPrivate: false - description: "" - sortKey: -1776615518572 - method: POST - body: - mimeType: application/json - text: "{\r - - \ //\"uuid\": null, // optional\r - - \ //\"currency\": null, // optional\r - - \ //\"sourceAddress\": null, // optional\r - - \ //\"transactionRef\": null, // optional\r - - \ //\"startTime\": null, // optional (timestamp)\r - - \ //\"endTime\": null, // optional (timestamp)\r - - \ //\"status\": [], // optional, list of - (PROCESSING, DONE, INVALID)\r - - \ \"limit\": 10, // (default 10)\r - - \ \"offset\": 0, // (default 0)\r - - \ \"ascendingByTime\": false // (default false)\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/transactions/withdraws" - name: Get Withdraw Transactions - meta: - id: req_d7a58e47bf904f2ebbf7a96733971b8c - created: 1776615524711 - modified: 1776615524711 - isPrivate: false - description: "" - sortKey: -1776615518571 - method: POST - body: - mimeType: application/json - text: "{\r - - \ // \"withdrawUuid\" : - \"764dfa79-cab4-403c-8526-049a80f13b69\", // optional\r - - \ //\"uuid\": null, // optional\r - - \ //\"currency\": null, // optional\r - - \ //\"destTxRef\": null, // optional\r - - \ //\"destAddress\": null, // optional\r - - \ //\"startTime\": null, // optional (timestamp)\r - - \ //\"endTime\": null, // optional (timestamp)\r - - \ //\"status\": [], // optional, list of - (REQUESTED,CREATED,ACCEPTED,CANCELED,REJECTED,DONE)\r - - \ \"limit\": 10, // (default 10)\r - - \ \"offset\": 0, // (default 0)\r - - \ \"ascendingByTime\": false // (default false)\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/transactions/swaps" - name: Get Swap Transactions - meta: - id: req_a6227b83ac0144a5bff49b972bb728e2 - created: 1776615524712 - modified: 1776615524712 - isPrivate: false - description: "" - sortKey: -1776615518570 - method: POST - body: - mimeType: application/json - text: "{\r - - \ //\"userId\": null, // optional\r - - \ //\"sourceSymbol\": null, // optional\r - - \ //\"destSymbol\": null, // optional\r - - \ //\"startTime\": null, // optional (timestamp)\r - - \ //\"endTime\": null, // optional (timestamp)\r - - \ \"limit\": 10, // (default 10)\r - - \ \"offset\": 0, // (default 0)\r - - \ \"ascendingByTime\": false, // (default false)\r - - \ \"status\" :\"Committed\" //(Created, Expired, Committed) - defualt = Committed\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/transactions/trades" - name: Get Trade Transactions Copy - meta: - id: req_18ab4cf87c744a62b317c52c0338c497 - created: 1776615524713 - modified: 1776615524713 - isPrivate: false - description: "" - sortKey: -1776615518569 - method: POST - body: - mimeType: application/json - text: "{\r - - \ //\"coin\": null, // optional\r - - \ //\"startTime\": null, // optional (timestamp)\r - - \ //\"endTime\": null, // optional (timestamp)\r - - \ \"limit\": 10, // (default 10)\r - - \ \"offset\": 0, // (default 0)\r - - \ \"ascendingByTime\": false // (default false)\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Wallet - meta: - id: fld_718b5feaa3744cc0b31866e3f4f08a68 - created: 1776615524715 - modified: 1776615524715 - sortKey: -1776615518568 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/admin/wallet/users" - name: Get Users Wallets - meta: - id: req_076bd7e7d27e45bab4fd6cac85987597 - created: 1776615524716 - modified: 1776615524716 - isPrivate: false - description: "" - sortKey: -1776615518567 - method: GET - parameters: - - name: uuid - value: "" - disabled: false - - name: currency - value: "" - disabled: false - - name: excludeSystem - value: "" - disabled: false - - name: limit - value: "10" - disabled: false - - name: offset - value: "0" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/wallet/system/total" - name: Get System Wallet Total - meta: - id: req_6fef8a73d32a405e9dfdc1368743d17a - created: 1776615524716 - modified: 1776615524716 - isPrivate: false - description: "" - sortKey: -1776615518566 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/wallet/users/total" - name: Get User Wallet Total - meta: - id: req_9f30b4048efa4f0c999c1ca174890a86 - created: 1776615524717 - modified: 1776615524717 - isPrivate: false - description: "" - sortKey: -1776615518565 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Withdraw - meta: - id: fld_901c082a80c44df3b50f4fcbeb04d881 - created: 1776615524718 - modified: 1776615524718 - sortKey: -1776615518564 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/admin/withdraw/manually/20_USDT/dcb7c726-8e0e-4\ - 0ba-a8c7-5a017905176d" - name: Withdraw Manually - meta: - id: req_43387134b36c40b0b7c7907cafa8a95f - created: 1776615524719 - modified: 1776615524719 - isPrivate: false - description: "" - sortKey: -1776615518563 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"description\":\"It is not nullable\",\r - - \ \"ref\":\"12345678999009\",\r - - \ \"attachment\":\"test\",\r - - \ \"gatewayUuid\":\"mag_f8ebdc5f-585f-4694-974c-9a29543d\ - 4a2b\"\r - - }" - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/withdraw/23b7c726-8e0e-40ba-a8c7-5a017905\ - 176d/done" - name: Done Withdraw - meta: - id: req_b422c98c2d74416587ae3ed8e5b82bcd - created: 1776615524720 - modified: 1776615524720 - isPrivate: false - description: "" - sortKey: -1776615518561 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"destTransactionRef\":\"0xsdf3j984fhe89fv834h893h\",\r - - \ \"destNote\":\"hi\",\r - - \ \"destAmount\":null,\r - - \ \"attachment\":\"test\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/withdraw/23b7c726-8e0e-40ba-a8c7-5a017905\ - 176d/accept" - name: Accept Withdraw - meta: - id: req_bcd236bb44ec403e894190a5721c74a9 - created: 1776615524720 - modified: 1776615524720 - isPrivate: false - description: "" - sortKey: -1776615518562 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/admin/withdraw/23b7c726-8e0e-40ba-a8c7-5a017905\ - 176d/reject" - name: Reject Withdraw - meta: - id: req_fafa4d87e1ce45b2960476e37074ddc4 - created: 1776615524721 - modified: 1776615524721 - isPrivate: false - description: "" - sortKey: -1776615518560 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"reason\":\"invalid address\",\r - - \ \"attachment\":\"test\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Deposit - meta: - id: fld_2b4a88e64f4141d5a186230d5c594fd5 - created: 1776615524722 - modified: 1776615524722 - sortKey: -1776615518559 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/admin/deposit/manually/20_USDT/dcb7c726-8e0e-40\ - ba-a8c7-5a017905176d" - name: Deposit Manually - meta: - id: req_21144d44c8c445298c63063c3c661118 - created: 1776615524723 - modified: 1776615524723 - isPrivate: false - description: "" - sortKey: -1776615518558 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"description\":\"test2\",\r - - \ \"ref\":\"123456988754483\",\r - - \ \"attachment\":\"test\",\r - - \ \"gatewayUuid\":\"mag_f8ebdc5f-585f-4694-974c-9a29543d\ - 4a2b\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Localization - meta: - id: fld_4bae2de52e4f48778491fb576c613736 - created: 1776948978232 - modified: 1778083336480 - sortKey: -1776948978232 - description: "" - children: - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/391f2f22-d6e1-4b08-9f30-ad1872ac14c\ - 0/localization" - name: Save Terminal Localozation - meta: - id: req_5f4586d3f3c449df96decdc0851f1923 - created: 1776768190645 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1776949037652 - method: POST - body: - mimeType: application/json - text: |- - [ - { - "description": "test 2", - "owner": "test 2", - "language": "EN" - }, - { - "description": "تست ۲", - "owner": "تست ۲", - "language": "FA" - } - ] - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/391f2f22-d6e1-4b08-9f30-ad1872ac14c\ - 0/localization" - name: Get Terminal Localization - meta: - id: req_50ea9123489d4be887b1e9d26168c491 - created: 1776768350923 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1776949037752 - method: GET - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] }}/opex/v1/admin/terminal/localization/24" - name: Delete Terminal Localization - meta: - id: req_05bfb23535e2435284be0cd855ffe6de - created: 1776768439323 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1776949037852 - method: DELETE - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] }}/opex/v1/admin/currency/IRT/localization" - name: Get Currency Localization - meta: - id: req_658103b61e454b46a4bf980da1d97081 - created: 1776949144966 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1776949144966 - method: GET - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] }}/opex/v1/admin/currency/IRT/localization" - name: Save Currency Localization - meta: - id: req_644cc832abd4497cb92b2d6cfa665951 - created: 1776949259843 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1776949091459 - method: POST - body: - mimeType: application/json - text: |- - [ - { - "name": "تومان", - "title": "تومان", - "alias": "ریال", - "description": "ارز ایران", - "shortDescription": "ارز ", - "language": "FA" - }, - { - "name": "toman", - "title": "toman", - "alias": "toman", - "description": "toman", - "shortDescription": "toman", - "language": "EN" - } - ] - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] }}/opex/v1/admin/currency/localization/22" - name: Delete currency localization - meta: - id: req_1b62c1077e7b4606a03b9d36e533e67a - created: 1776949318083 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1776949051328.75 - method: PUT - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4e596e2\ - 9cc7/localization" - name: Save Gateway Localization - meta: - id: req_b188873d030c4a388ccf6a269a52609e - created: 1777735868520 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777735868520 - method: POST - body: - mimeType: application/json - text: |- - [ - { - "depositDescription": "گیت وی", - "withdrawDescription": "گیت وی", - "language":"FA" - } - ] - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4e596e2\ - 9cc7/localization" - name: Get Gateway Localization - meta: - id: req_d6c262f9b46f49e7bd1fefd1621d9cc8 - created: 1777735910142 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777735910142 - method: GET - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4e596e2\ - 9cc7/localization/2" - name: Delete Gateway Localization - meta: - id: req_3c92884a9b644112a946d9e494b15cd7 - created: 1777735941100 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777735941100 - method: DELETE - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Terminal & Gateway - meta: - id: fld_2fdedb573d38479c9abe20f37b025bbc - created: 1777893915002 - modified: 1778083336480 - sortKey: -1777893915002 - description: "" - children: - - url: "{{ _['api-host'] }}/opex/v1/admin/terminal" - name: Save Terminal - meta: - id: req_1460445827d64fa9b23e2fe9dca73231 - created: 1777893920101 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777893920101 - method: POST - body: - mimeType: application/json - text: |- - { - "owner": "فاطمه ایمانی ور", - "identifier": "5057851017634988", - "active": true, - "type": "CARD", - "metaData": "izb", - "description": "Valid For 1 Day", - "displayOrder": 1 - } - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ - c" - name: Update Terminal - meta: - id: req_1b6fafd29afb47a2815f0a2bf62c2155 - created: 1777894228030 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777874172725.875 - method: PUT - body: - mimeType: application/json - text: |- - { - "owner": "فاطمه ایمانی ور", - "identifier": "5057851017634988", - "active": true, - "type": "CARD", - "metaData": "izb", - "description": "Valid For 1 Day", - "displayOrder": 1 - } - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ - c" - name: Delete Terminal - meta: - id: req_7a1a2d85f5ad4adf8f3ab3e03048dd25 - created: 1777894267178 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777856893772.6406 - method: DELETE - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ - c" - name: Get Terminal - meta: - id: req_c3e805c1450843128fed3b792e257b0f - created: 1777894298007 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777864299038.3125 - method: GET - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] }}/opex/v1/admin/terminal" - name: Get Terminals - meta: - id: req_8e2f73ac76f245a88d66e9271d7d98f3 - created: 1777894318403 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777859362194.5312 - method: GET - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/cbdfa3e2-3f94-41cc-b53c-967ded4f0d8\ - c/gateway" - name: Get Gateway Terminal - meta: - id: req_96838e5f4c6b49beb75cbc0b63e4f977 - created: 1777894363527 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777893920126 - method: GET - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/gateway/aadfa3e2-3f94-41cc-b53c-967\ - ded4f0dpo" - name: Assign Terminal To Gateway - meta: - id: req_252425572ad641cfbccb29664d13628f - created: 1777894401365 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777854425350.75 - method: POST - body: - mimeType: application/json - text: '["e360a8cb-a594-486c-a221-5be94d1e122b","gh360cb-a594-486c-a881-5be94d1emmm"]' - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/terminal/gateway/aadfa3e2-3f94-41cc-b53c-967\ - ded4f0dpo" - name: Revoke Terminal From Gateway - meta: - id: req_06490d89ca1b40e486022698e938eff6 - created: 1777894500460 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777834677975.625 - method: DELETE - body: - mimeType: application/json - text: '["e360a8cb-a594-486c-a221-5be94d1e122b","gh360cb-a594-486c-a881-5be94d1emmm"]' - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/currency/gateway" - name: Get Gateways - meta: - id: req_a350d09ac9564e05b90b2895fcd0a463 - created: 1777894610657 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777893920201 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/gateway/e360a8cb-a594-486c-a221-5be94d1e\ - 122b/terminal" - name: "Get Terminal Gateway " - meta: - id: req_8359bedf3865476b8c378088c4bc396d - created: 1777894705788 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777893920113.5 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] }}/opex/v1/admin/BTC/gateway" - name: Add Currency To Gateway - meta: - id: req_5be974c7827341d581fea4619c8f80f7 - created: 1777894821253 - modified: 1778083336480 - isPrivate: false - description: |- - { - "type": "OffChain", // Card2card, Sheba, IPG - "depositMin": 0.1, - "depositMax": 10, - "withdrawMin": 2, - "withdrawMax": 5, - "isActive": true, - "withdrawFee": 0.001, - "withdrawAllowed": false, - "depositAllowed": true, - "displayOrder" : 1 - - "transferMethod": "IPG" - } - { - "type": "OnChain", - "depositMin": 0.1, - "depositMax": 10, - "withdrawMin": 2, - "withdrawMax": 5, - "isActive": true, - "withdrawFee": 0.001, - "withdrawAllowed": false, - "depositAllowed": false, - "tokenName": null, - "tokenAddress": null, - "implementationSymbol": "tes444489998899ggh", - "isToken": false, - "decimal": 18, - "chain": "test-bitcoin", - "displayOrder" : 1 - - } - sortKey: -1777893920301 - method: POST - body: - mimeType: application/json - text: |- - { - "type": "OnChain", - "depositMin": 0.1, - "depositMax": 10, - "withdrawMin": 2, - "withdrawMax": 5, - "isActive": true, - "withdrawFee": 0.001, - "withdrawAllowed": false, - "depositAllowed": false, - "tokenName": null, - "tokenAddress": null, - "implementationSymbol": "tes44dassa99ggh", - "isToken": false, - "decimal": 18, - "chain": "test-bitcoin", - "displayOrder" : 1 - - } - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/BTC/gateway/e360a8cb-a594-486c-a221-5be94d1e\ - 122b" - name: Update Gateway - meta: - id: req_5fcfcd705c634e22bb344a09ab8eecb7 - created: 1777895166941 - modified: 1778083336480 - isPrivate: false - description: |- - { - "type": "OffChain", // Card2card, Sheba, IPG - "depositMin": 0.1, - "depositMax": 10, - "withdrawMin": 2, - "withdrawMax": 5, - "isActive": true, - "withdrawFee": 0.001, - "withdrawAllowed": false, - "depositAllowed": true, - "displayOrder" : 1 - - "transferMethod": "IPG" - } - { - "type": "OnChain", - "depositMin": 0.1, - "depositMax": 10, - "withdrawMin": 2, - "withdrawMax": 5, - "isActive": true, - "withdrawFee": 0.001, - "withdrawAllowed": false, - "depositAllowed": false, - "tokenName": null, - "tokenAddress": null, - "implementationSymbol": "tes444489998899ggh", - "isToken": false, - "decimal": 18, - "chain": "test-bitcoin", - "displayOrder" : 1 - - } - sortKey: -1777893920251 - method: PUT - body: - mimeType: application/json - text: |- - { - "type": "OnChain", - "depositMin": 0.1, - "depositMax": 10, - "withdrawMin": 2, - "withdrawMax": 5, - "isActive": true, - "withdrawFee": 0.001, - "withdrawAllowed": false, - "depositAllowed": false, - "tokenName": null, - "tokenAddress": null, - "implementationSymbol": "tes44dassa99ggh", - "isToken": false, - "decimal": 18, - "chain": "test-bitcoin", - "displayOrder" : 1 - - } - headers: - - name: Content-Type - value: application/json - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/BTC/gateway/e360a8cb-a594-486c-a221-5be94d1e\ - 122b" - name: Get Gateway - meta: - id: req_30fdabfe534f48ce99f90387b17c5288 - created: 1777895205056 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777893920176 - method: GET - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{ _['api-host'] - }}/opex/v1/admin/BTC/gateway/e360a8cb-a594-486c-a221-5be94d1e\ - 122b" - name: Delete Gateway - meta: - id: req_bc75f9f9cc5d4652a5de7004062ac332 - created: 1777895318852 - modified: 1778083336480 - isPrivate: false - description: "" - sortKey: -1777893920151 - method: DELETE - headers: - - name: User-Agent - value: insomnia/12.5.0 - description: "" - disabled: false - authentication: - type: bearer - token: "{{ _['admin-token'] }}" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Profile - meta: - id: fld_a6e07a1838b34abda78e52114a202d34 - created: 1776615524724 - modified: 1776615524724 - sortKey: -1776615518557 - description: "" - children: - - url: https://api.opex.dev:8443/auth/realms/opex/user-profile - name: Get Attributes - meta: - id: req_02be52f319904bb980b308395f4f4fae - created: 1776615524756 - modified: 1776615524756 - isPrivate: false - description: "" - sortKey: -1776615518522 - method: GET - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtWlJ1S0w3UW1ibEYyNm8yNXp3MnNaanRqYTB1RkZrVnJQLVJlTUtpTmw4In0.eyJleHAiOjE2NTExMDE4MzMsImlhdCI6MTY1MTA2NTgzMywianRpIjoiN2ZjYmZhNjktMzM5ZC00OWY3LWEzNzMtZDk3NGQ0NTdiMjMyIiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjBmMDBiMWMxLTcyODMtNGY2Ny1hZDFmLTkzMjI3MTJhZDljNyIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZTFiOGM2NjAtY2U1NC00ODFmLTlmNzktZDhkYTU5ZmE4ZDBjIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2K3Ys9uM2YYg2KfYqNmI2KfZhNit2LPZhtuMIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGVtbzFAb3BleC5kZXYiLCJnaXZlbl9uYW1lIjoi2K3Ys9uM2YYiLCJmYW1pbHlfbmFtZSI6Itin2KjZiNin2YTYrdiz2YbbjCIsImVtYWlsIjoiZGVtbzFAb3BleC5kZXYifQ.MtvaH4D8NUDUFQLJcH1vI2x-3HOtnHqImaMvXdvAnrMjuQo6kZRzi0G_K7-jr3pYM39BJP6m25AqvyIWkn8bH8ctD-e_eKILohNnnBdDttzqTxBkc4ozWo5ELHj8-FBJgmdASXY0FKT2yTTeFSDy8bK-I1xTx1LU438J3BaRIhIp6O0zx58Vw_82iUfMgyP_u_p1NFh1Si04DHD42fGgWLPreflUY64DTTmr2WZ7kgzg45N3R7twDMfkGCXlqSRWLmquok0n9SH9REhUYq16BvoKXTBWiux4wYZRhL2wZIqba6EV1WgiC9uiHU5biQCv3wvw1jxkPOvfNd-rhdn83A - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev:8443/auth/realms/opex/user-profile - name: Add Attributes - meta: - id: req_6245034796544502a9f2f0bd601eb90b - created: 1776615524757 - modified: 1776615524757 - isPrivate: false - description: "" - sortKey: -1776615518521 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"firstNameEn\":\"a\",\r - - \ \"lastNameEn\":\"b\",\r - - \ \"firstName\":\"حسین\",\r - - \ \"lastName\":\"b\",\r - - \ \"birthdayJ\":\"01/06/1375\",\r - - \ \"birthdayG\":\"22/08/1996\",\r - - \ \"nationalId\":\"111111111\",\r - - \ \"passportNumber\":\"sfcdfvdfvxc\",\r - - \ \"mobile\":\"09383381451\",\r - - \ \"telephone\":\"02133253214\",\r - - \ \"postalCode\":\"1718614644\",\r - - \ \"residence\":\"\",\r - - \ \"nationality\":\"\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtWlJ1S0w3UW1ibEYyNm8yNXp3MnNaanRqYTB1RkZrVnJQLVJlTUtpTmw4In0.eyJleHAiOjE2NTExMDE4MzMsImlhdCI6MTY1MTA2NTgzMywianRpIjoiN2ZjYmZhNjktMzM5ZC00OWY3LWEzNzMtZDk3NGQ0NTdiMjMyIiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjBmMDBiMWMxLTcyODMtNGY2Ny1hZDFmLTkzMjI3MTJhZDljNyIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZTFiOGM2NjAtY2U1NC00ODFmLTlmNzktZDhkYTU5ZmE4ZDBjIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2K3Ys9uM2YYg2KfYqNmI2KfZhNit2LPZhtuMIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGVtbzFAb3BleC5kZXYiLCJnaXZlbl9uYW1lIjoi2K3Ys9uM2YYiLCJmYW1pbHlfbmFtZSI6Itin2KjZiNin2YTYrdiz2YbbjCIsImVtYWlsIjoiZGVtbzFAb3BleC5kZXYifQ.MtvaH4D8NUDUFQLJcH1vI2x-3HOtnHqImaMvXdvAnrMjuQo6kZRzi0G_K7-jr3pYM39BJP6m25AqvyIWkn8bH8ctD-e_eKILohNnnBdDttzqTxBkc4ozWo5ELHj8-FBJgmdASXY0FKT2yTTeFSDy8bK-I1xTx1LU438J3BaRIhIp6O0zx58Vw_82iUfMgyP_u_p1NFh1Si04DHD42fGgWLPreflUY64DTTmr2WZ7kgzg45N3R7twDMfkGCXlqSRWLmquok0n9SH9REhUYq16BvoKXTBWiux4wYZRhL2wZIqba6EV1WgiC9uiHU5biQCv3wvw1jxkPOvfNd-rhdn83A - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev:8443/auth/realms/opex/user-profile/kyc/status - name: KYC Status - meta: - id: req_446f5249c75d499b99c9a2d77f42df80 - created: 1776615524758 - modified: 1776615524758 - isPrivate: false - description: "" - sortKey: -1776615518520 - method: GET - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiajc2MUtyM2U4cl9LUEZjU19VRGtHNUFTN2szcGNJd1FiNmFqX3RoaTEwIn0.eyJleHAiOjE2NTI4NjYxOTksImlhdCI6MTY1Mjc3OTc5OSwianRpIjoiN2ZhNjNiZTEtMDgxOC00M2NlLWExZjktNzFiZDhhMWZiZTJkIiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6ImRlMTdhMmNmLTg3ZGItNDAwZi04Yjc5LTRlYjg1MWNlMjkwZSIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiNjUyNTQ3ODAtZmY4NS00YTBlLWExMWMtODU0YTAwNDk2ZDEyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2qnYp9ix2KjYsSDZhtmF2KfbjNi024wiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJkZW1vMUBvcGV4LmRldiIsImdpdmVuX25hbWUiOiLaqdin2LHYqNixIiwiZmFtaWx5X25hbWUiOiLZhtmF2KfbjNi024wiLCJlbWFpbCI6ImRlbW8xQG9wZXguZGV2In0.R2jpuGAJwtspDm6mIxG4ts7N-DrlMGixU63PGBL_FfaL7q-hUcyi5rnFe-xGVa-EfrfGzuPfWW5O_WRHbM9YiBvfuKEgELbfi9GYY86GJyqHZ7qPE1MB8T-zglPD48oSYTYv8HhbsN1g6DNkVNrex6k0Dp8C5jVwjwChew8SPE3d86gzHCL4l4X3vqG-aonoyjmE37CResDYwtiklK9mmuk3I-ji1xjdmHpVkEtWw0DBlX2TRfNpo9G1M-uqPySeDe3gkIYuakx899uREcnXpMVxRc3aqXN6_XtiS7jSyKhYTWxVneNIxnyE1i-YkaEB4riPFM0_wmToYvmGFnPBOg - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev:8443/auth/realms/opex/user-profile/kyc - name: KYC Image Paths - meta: - id: req_27b427f80506494a9eabbf6c116d7f47 - created: 1776615524759 - modified: 1776615524759 - isPrivate: false - description: "" - sortKey: -1776615518519 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"selfiePath\":\"/0d510617-5505-4ed6-b6b8-b1df5a4ff784/70e\ - a5067.png\",\r - - \ \"idCardPath\":\"/0d510617-5505-4ed6-b6b8-b1df5a4ff784/70e\ - a5068.png\",\r - - \ \"acceptFormPath\":\"/0d510617-5505-4ed6-b6b8-b1df5a4ff784\ - /70ea5069.png\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtWlJ1S0w3UW1ibEYyNm8yNXp3MnNaanRqYTB1RkZrVnJQLVJlTUtpTmw4In0.eyJleHAiOjE2NTEzNDAyMDksImlhdCI6MTY1MTMwNDIwOSwianRpIjoiMGE4YzQ1MjMtMjliYy00MjA0LTkxYmYtNGU1NDZjMmI2OGY0IiwiaXNzIjoiaHR0cHM6Ly9kZW1vLm9wZXguZGV2Ojg0NDMvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjBmMDBiMWMxLTcyODMtNGY2Ny1hZDFmLTkzMjI3MTJhZDljNyIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiYzhiMmQyNWEtNGVjYi00NTk3LWJjYzItMTU5ZmViYWIwODkyIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJuYW1lIjoi2qnYp9ix2KjYsSDZhtmF2KfbjNi024wg24zaqdmFIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGVtbzFAb3BleC5kZXYiLCJnaXZlbl9uYW1lIjoi2qnYp9ix2KjYsSDZhtmF2KfbjNi024wiLCJmYW1pbHlfbmFtZSI6ItuM2qnZhSIsImVtYWlsIjoiZGVtbzFAb3BleC5kZXYifQ.pS5yJNGDsXGXjXPC7eGrryW79S1jvqzBezuUo6DRQy19qEJBAfAjlArNFZgf--Pucii9sj08KVqrzA5C0fHCFRydb42PNuj04WtquxBllifUWj77ycw3skA4u9m5s4jlpJvCXgQFC2oMcNP405e7999eGUKxpcI6tCdA4917shAylWyoGrSKVY5BpQ1_W7gSKk0HeLCciqnqwM3og9N1LQomWXeZcjGl0UtaOpCC52IWMp5yM_WEw5UrhKM4Du7nOI5v7Nq2S8t6c4JIYZLwvqcGLyAe1ZZGQSKADkyNwoelbCsXMTOqUQOJgB4_XgggonUJpQCkg2_3csPLLU4Zww - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: v2 - meta: - id: fld_d96b1e84fff44a1899cde30bb304a56a - created: 1776615524725 - modified: 1776615524725 - sortKey: -1776615518556 - description: "" - children: - - name: user - meta: - id: fld_c7e41b315d6e44319d99df33d1c8955c - created: 1776615524726 - modified: 1776615524726 - sortKey: -1776615518555 - description: "" - children: - - url: localhost:8079/v2/profile - name: Update profile - meta: - id: req_96ec572d0fe74771b59bd6ff31e117c5 - created: 1776615524726 - modified: 1776615524726 - isPrivate: false - description: "" - sortKey: -1776615518554 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"firstName\": \"fatemeh\",\r - - \ \"lastName\": \"imanipour\",\r - - \ \"address\": \"tehran\",\r - - \ \"telephone\": \"7733445566\",\r - - \ \"postalCode\": \"169876543\",\r - - \ \"nationality\": \"iranian\",\r - - \ \"identifier\": \"0019002602\",\r - - \ \"gender\": \"Female\",\r - - \ \"mobile\": \"09905135295\",\r - - \ \"birthDate\": \"2020-06-15T00:00:00\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/profile/linked-account - name: Add linked bank account - meta: - id: req_d8993c30b8294cd6b6cb1725d7fd6d3c - created: 1776615524727 - modified: 1776615524727 - isPrivate: false - description: "" - sortKey: -1776615518553 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"bankAccountType\":\"Sheba\",\r - - \ \"number\":\"480690011980901162627001\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/profile/linked-account - name: Get linked bank account - meta: - id: req_2de7aa45c42b4f9a97955ca5715a932d - created: 1776615524728 - modified: 1776615524728 - isPrivate: false - description: "" - sortKey: -1776615518552 - method: GET - body: - mimeType: application/json - text: "{\r - - \ \"bankAccountType\":\"Sheba\",\r - - \ \"number\":\"480690011980901162627001\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/profile/linked-account/b9fc8d36-60f9-4c91-807f-3205201f6fa - name: update linked account(enable,disable) - meta: - id: req_56c326653fa04f7f96674542e04cd114 - created: 1776615524729 - modified: 1776615524729 - isPrivate: false - description: "" - sortKey: -1776615518551 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"status\":\"Disable\" //Enable\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/admin/profile/limitation - name: Get limitation - meta: - id: req_64378484383641199eff5d6141893270 - created: 1776615524731 - modified: 1776615524731 - isPrivate: false - description: "" - sortKey: -1776615518550 - method: GET - body: - mimeType: multipart/form-data - params: - - name: action - value: CashOut - disabled: true - type: text - - name: userId - value: 27396a77-797c-47c4-b2cb-4a8e5c9034fd - disabled: true - type: text - - name: size - value: "3" - disabled: true - type: text - - name: offset - value: "2" - disabled: true - type: text - - name: reason - value: MajorProfileChange - disabled: true - type: text - - name: groupBy - value: reason - disabled: true - type: text - headers: - - name: Content-Type - value: multipart/form-data - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/profile/linked-account/b9fc8d36-60f9-4c91-807f-3205201f6faf - name: Delete linked account - meta: - id: req_ea6c4e8bb1f74dadb54badcefcfa7ef5 - created: 1776615524731 - modified: 1776615524731 - isPrivate: false - description: "" - sortKey: -1776615518549 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: https://api.opex.dev/profile/v2/profile - name: Get profile - meta: - id: req_bd2ad7d9e7614ce587a32f9202b0958a - created: 1776615524733 - modified: 1776615524733 - isPrivate: false - description: "" - sortKey: -1776615518548 - method: GET - authentication: - type: bearer - disabled: false - token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NTI5NDIzNzQsImlhdCI6MTc1MjkzODc3NCwianRpIjoiN2VkMDlhY2YtYTFkNC00ZDQxLTg4YWUtNDhjNWQ1ZDY2MTA1IiwiaXNzIjoiaHR0cDovL2tjLm9wZXguZGV2OjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJvcGV4LWFwaS1rZXkiLCJzdWIiOiIwMGVlYTRiZi0xOWJkLTRhODQtOGQ2NS0xMzY2ZTRmYTcxYTkiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiOWNhMDMxYTAtZTNiZS00MTBmLWJhNWQtZGNiNTM0YTI1MzQyIiwic2NvcGUiOiJ0cnVzdCIsImZpcnN0TmFtZSI6IkFtaXIiLCJsYXN0TmFtZSI6IlJhamFiaSIsInBlcm1pc3Npb25zIjpbImRlcG9zaXQ6d3JpdGUiLCJvcmRlcjp3cml0ZSIsImFkZHJlc3M6YXNzaWduIiwiZGVwb3NpdDp3cml0ZSJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJkZWZhdWx0LXJvbGVzLW9wZXgiLCJ1c2VyIl0sIm1vYmlsZSI6IjA5OTgxMzkwOTA5IiwidXNlcm5hbWUiOiIwOTk4MTM5MDkwOSJ9.UPmGazBmuK1IqJW_mFoRbDSehMF9yLK34jUBhdkvf_ytdRKhzrkPouVpG9ITTtN7WkZJFfx0Tv-_4FmXCv1NSiBQDkX10bVT5THWXiMuhAWk1QT2-xWQYCR656q-VMcJ8S_6GPE7rD-k4zrd0J02t8ZTYF9dMvPsHqqmA_griY24kG9AtGePmqQl53Ul-jaGfMUnixNmz613PGXWNrybGBGUz0DwGNRsxoNbWcJwqfHZ3ZT-vDOVr7JwPau3_P2KSEWc7DkgB5qg7TWSeJ5VPn4aLaL8HnrM8kL1Aql16ByYbWnqqYlNNAR07ER6AwQsIrZ6-iPgIlpDXwJ8mTAx1w - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: admin - meta: - id: fld_cff1106c35f346e0b406a4db18d31824 - created: 1776615524733 - modified: 1776615524733 - sortKey: -1776615518547 - description: "" - children: - - url: localhost:8079/v2/profile - name: Update profile - meta: - id: req_a0be82791bef463abcb5a7ee9d62e885 - created: 1776615524734 - modified: 1776615524734 - isPrivate: false - description: "" - sortKey: -1776615518546 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"firstName\": \"fatemeh\",\r - - \ \"lastName\": \"imanipour\",\r - - \ \"address\": \"tehran\",\r - - \ \"telephone\": \"7733445566\",\r - - \ \"postalCode\": \"169876543\",\r - - \ \"nationality\": \"iranian\",\r - - \ \"identifier\": \"0019002602\",\r - - \ \"gender\": \"Female\",\r - - \ \"mobile\": \"09905135295\",\r - - \ \"birthDate\": \"2020-06-15T00:00:00\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/admin/profile/history/27396a77-797c-47c4-b2cb-4a8e5c9034fd - name: Get profile history - meta: - id: req_361674d9ad5946afbded6f482b234f8e - created: 1776615524735 - modified: 1776615524735 - isPrivate: false - description: "" - sortKey: -1776615518545 - method: GET - body: - mimeType: application/json - text: "{\r - - \ \"firstName\": \"fatemeh\",\r - - \ \"lastName\": \"imanipour\",\r - - \ \"address\": \"tehran\",\r - - \ \"telephone\": \"7733445566\",\r - - \ \"postalCode\": \"169876543\",\r - - \ \"nationality\": \"iranian\",\r - - \ \"identifier\": \"0019002602\",\r - - \ \"gender\": \"Female\",\r - - \ \"mobile\": \"09905135295\",\r - - \ \"birthDate\": \"2020-06-15T00:00:00\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/admin/profile/linked-account/verify/a4d85bd2-cc50-4b01-9e43-4511a4a738fa - name: Verify an account - meta: - id: req_0a98a443d20543a4bc45613ef0093e81 - created: 1776615524736 - modified: 1776615524736 - isPrivate: false - description: "" - sortKey: -1776615518543 - method: PUT - body: - mimeType: application/json - text: "{\"description\":\"beautiful name\",\r - - \"verified\":true}" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/admin/profile/linked-account/history/a4d85bd2-cc50-4b01-9e43-4511a4a738fa - name: Get history of an account - meta: - id: req_f6aae0efb0af45ac96da6a73d0d45e9a - created: 1776615524736 - modified: 1776615524736 - isPrivate: false - description: "" - sortKey: -1776615518544 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "" - name: Set limitations - meta: - id: req_fd8a7a2675a2436287ad515cd5af3cf3 - created: 1776615524737 - modified: 1776615524737 - isPrivate: false - description: "" - sortKey: -1776615518542 - method: POST - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/admin/profile/limitation - name: Get limitation - meta: - id: req_c3cddc1a021646118791e4d917a6e2cd - created: 1776615524738 - modified: 1776615524738 - isPrivate: false - description: "" - sortKey: -1776615518541 - method: GET - body: - mimeType: multipart/form-data - params: - - name: action - value: CashOut - disabled: true - type: text - - name: userId - value: 27396a77-797c-47c4-b2cb-4a8e5c9034fd - disabled: true - type: text - - name: size - value: "3" - disabled: true - type: text - - name: offset - value: "2" - disabled: true - type: text - - name: reason - value: MajorProfileChange - disabled: true - type: text - - name: groupBy - value: reason - disabled: true - type: text - headers: - - name: Content-Type - value: multipart/form-data - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8079/v2/admin/profile/limitation/history - name: Get limitation history - meta: - id: req_ff6e994b657e43b3a10b6a99ca28b834 - created: 1776615524739 - modified: 1776615524739 - isPrivate: false - description: "" - sortKey: -1776615518540 - method: GET - body: - mimeType: multipart/form-data - params: - - name: action - value: CashOut - disabled: true - type: text - - name: userId - value: All - disabled: true - type: text - - name: size - value: "3" - disabled: true - type: text - - name: offset - value: "2" - disabled: true - type: text - headers: - - name: Content-Type - value: multipart/form-data - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['admin-host']}}/admin/v2/profile" - name: get Profile - meta: - id: req_e5a961ca3e4745de9e0311b4a4171164 - created: 1776615524740 - modified: 1776615524740 - isPrivate: false - description: "" - sortKey: -1776615518539 - method: POST - body: - mimeType: application/json - text: "{\r - - \"includeLimitation\":true,\r - - \"includeLinkedAccount\":true,\r - - \"partialSearch\":true,\r - - \"userId\":\"27\",\r - - \"firstName\":\"fate\",\r - - \"lastName\":\"imani\",\r - - \"nationalCode\":\"0019\",\r - - \"email\":\"imanipour\",\r - - \"createDateFrom\":\"2023-08-22T14:36:06\",\r - - \"createDateTo\":\"2023-08-23T14:36:06\",\r - - \"mobile\":\"09\"//,\r - - //\"accountNumber\":\"\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Completion - meta: - id: fld_409b7373d99347d09aca78b949cd5f2f - created: 1776615524741 - modified: 1776615524741 - sortKey: -1776615518538 - description: "" - children: - - url: "{{_['profile-host']}}/approval-request" - name: Get Profile Approval Request - meta: - id: req_4d27f2a8e47442f0bb2d1a837407b518 - created: 1776615524742 - modified: 1776615524742 - isPrivate: false - description: "" - sortKey: -1776615518536 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/personal-data" - name: Get Profile - meta: - id: req_fe99b7bc8a6741c7b147afbf7172a435 - created: 1776615524742 - modified: 1776615524742 - isPrivate: false - description: "" - sortKey: -1776615518537 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/contact/update/otp-request" - name: Request Update(email or mobile) - meta: - id: req_72ffeed4f2364a26b988b759253990fc - created: 1776615524743 - modified: 1776615524743 - isPrivate: false - description: "" - sortKey: -1776615518535 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"mobile\" : \"09212880961\"\r - - \ // \"email\" : \"amir@gmail.com\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/contact/update/otp-verification" - name: Verify Update(email or mobile) - meta: - id: req_3cca58962d694458b7369bd4928e4cda - created: 1776615524744 - modified: 1776615524744 - isPrivate: false - description: "" - sortKey: -1776615518534 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ // \"email\" : \"amir@gmail.com\"\r - - \ \"mobile\" : \"09212880961\",\r - - \ \"otpCode\" :\"612354\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/completion" - name: Completion - meta: - id: req_99caf67a0c4846f29dfcba4f7c9a8be0 - created: 1776615524745 - modified: 1776615524745 - isPrivate: false - description: "" - sortKey: -1776615518533 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"firstName\": \"امیر\",\r - - \ \"lastName\": \"رجبی\",\r - - \ \"address\": \"tehran\",\r - - \ // \"telephone\": \"7733445566\",\r - - \ // \"postalCode\": \"169876543\",\r - - \ \"nationality\": \"IRANIAN\", - // IRANIAN,NON_IRANIAN\r - - \ \"identifier\": \"0025018108\",\r - - \ \"gender\": \"MALE\",\r - - \ \"birthDate\": \"2002-06-29T00:00:00\"\r - - }" - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Bank Account - meta: - id: fld_b53eb74719ec427aa668d571a662a0bb - created: 1776615524746 - modified: 1776615524746 - sortKey: -1776615518532 - description: "" - children: - - url: "{{_['profile-host']}}/bank-account" - name: Add bank account - meta: - id: req_058775e477004b9ca076b7385adcc8b0 - created: 1776615524747 - modified: 1776615524747 - isPrivate: false - description: "" - sortKey: -1776615518531 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"name\" : \"amir\",\r - - \ // \"cardNumber\" : \"5057851031070300\"\r - - \ \"iban\" : \"IR560690016783002286017001\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/bank-account" - name: Get all bank account - meta: - id: req_beaf3b7a30cc421697d01fddba6db29f - created: 1776615524748 - modified: 1776615524748 - isPrivate: false - description: "" - sortKey: -1776615518530 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/bank-account/8" - name: Delete bank account - meta: - id: req_8be6236e594841f7a5171e35132732fb - created: 1776615524749 - modified: 1776615524749 - isPrivate: false - description: "" - sortKey: -1776615518529 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/bank-account/ownership" - name: Validate ownership ( for ipg ) - meta: - id: req_e73c4a8a68af4bcb95befacaba6f2bbf - created: 1776615524750 - modified: 1776615524750 - isPrivate: false - description: "" - sortKey: -1776615518528 - method: GET - parameters: - - name: cardNumber - value: "6219861902618981" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Address Book - meta: - id: fld_00b9e73e9d034259ac993a72329f5980 - created: 1776615524751 - modified: 1776615524751 - sortKey: -1776615518527 - description: "" - children: - - url: "{{_['profile-host']}}/address-book" - name: Get all address book items - meta: - id: req_df56036e5b3c4aa1930e3c24d68eee67 - created: 1776615524752 - modified: 1776615524752 - isPrivate: false - description: "" - sortKey: -1776615518526 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/address-book" - name: Save address book item - meta: - id: req_50c277c1ba7a4a1780d127b98d392ab7 - created: 1776615524753 - modified: 1776615524753 - isPrivate: false - description: "" - sortKey: -1776615518525 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"name\" : \"tes2t\",\r - - \ \"address\" : \"test31234\",\r - - \ \"addressType\" : \"BCS\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/address-book/8" - name: Delete address book item - meta: - id: req_951e6f23fda54e27a8ceaa080fb4d5de - created: 1776615524754 - modified: 1776615524754 - isPrivate: false - description: "" - sortKey: -1776615518524 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['profile-host']}}/address-book/3" - name: Update Address book item - meta: - id: req_983c7e04052c4763b797d9c432a663eb - created: 1776615524755 - modified: 1776615524755 - isPrivate: false - description: "" - sortKey: -1776615518523 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"name\" : \"testtest\",\r - - \ \"address\" : \"test123445\",\r - - \ \"addressType\" : \"BCS\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Landing - meta: - id: fld_4193c9540f744ccd922f29b0651895a7 - created: 1776615524759 - modified: 1776615524759 - sortKey: -1776615518518 - description: "" - children: - - url: "{{_['api-host']}}/v1/landing/marketStats" - name: Market stats - meta: - id: req_7392f312f59040a6b26fe14dd8811f92 - created: 1776615524760 - modified: 1776615524760 - isPrivate: false - description: "" - sortKey: -1776615518517 - method: GET - parameters: - - name: interval - value: 24H - disabled: false - - name: limit - value: "10" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/landing/exchangeInfo" - name: Exchange info - meta: - id: req_a40deb7301c3454dbabdf62011d99dbb - created: 1776615524761 - modified: 1776615524761 - isPrivate: false - description: "" - sortKey: -1776615518516 - method: GET - parameters: - - name: interval - value: 3M - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/v1/landing/globalPrices" - name: Global prices - meta: - id: req_0b674c1c4009486fa25d1d5eaa77db1f - created: 1776615524762 - modified: 1776615524762 - isPrivate: false - description: "" - sortKey: -1776615518515 - method: GET - parameters: - - name: usdSymbol - value: TUSDT - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: kyc - meta: - id: fld_af696082669141c4913956f5f324d4d4 - created: 1776615524763 - modified: 1776615524763 - sortKey: -1776615518514 - description: "" - children: - - name: user - meta: - id: fld_cb97863390f14db09fc456e0c16e50af - created: 1776615524764 - modified: 1776615524764 - sortKey: -1776615518513 - description: "" - children: - - url: localhost:8078/v2/kyc/upload - name: Upload images for level2 - meta: - id: req_df22cb319b394212accafb929f27e0ae - created: 1776615524765 - modified: 1776615524765 - isPrivate: false - description: "" - sortKey: -1776615518512 - method: POST - body: - mimeType: multipart/form-data - params: - - name: files - disabled: false - fileName: /C:/Users/imani/Downloads/fatemeh_idcard2 (1).jpeg - type: file - headers: - - name: Content-Type - value: multipart/form-data - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "" - name: Get user's kyc steps - meta: - id: req_bc9a440dcab244b3a5dc876e80e6b4b1 - created: 1776615524766 - modified: 1776615524766 - isPrivate: false - description: "" - sortKey: -1776615518511 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "" - name: Get details of step - meta: - id: req_8c42a980784a4a2992a175a328e4dd07 - created: 1776615524767 - modified: 1776615524767 - isPrivate: false - description: "" - sortKey: -1776615518510 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: admin - meta: - id: fld_fedb76c031cd4a8581df220537547aa5 - created: 1776615524768 - modified: 1776615524768 - sortKey: -1776615518509 - description: "" - children: - - url: localhost:8078/v2/admin/kyc/review/a1840f95-d542-4754-afda-c0bb8e3cabeb - name: Review uploaded files - meta: - id: req_40ca686e99f04f709d673ffe6c68ca4d - created: 1776615524768 - modified: 1776615524768 - isPrivate: false - description: "" - sortKey: -1776615518508 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"status\":\"Accepted\", //Rejected\r - - \ \"description\":\"Beautiful Image\",\r - - \ \"userId\":\"d8c107ee-5f23-496a-9d96-8646fd535d36\"\r - - }\r\n" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8078/v2/admin/kyc/d8c107ee-5f23-496a-9d96-8646fd535d36 - name: Update kyc level manually - meta: - id: req_33b7bb1058c546db97ec4ebd8787c4ad - created: 1776615524769 - modified: 1776615524769 - isPrivate: false - description: "" - sortKey: -1776615518507 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"level\":\"ManualUpdateLevel1\", - //ManualUpdateLevel2\r - - \ \"description\":\"ugly Image\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8078/v2/admin/kyc/step - name: Get Users' kyc steps - meta: - id: req_063d2b5f1d8c4f488cd88e81d9bef02b - created: 1776615524770 - modified: 1776615524770 - isPrivate: false - description: "" - sortKey: -1776615518506 - method: GET - body: - mimeType: multipart/form-data - params: - - name: userId - value: d8c107ee-5f23-496a-9d96-8646fd535d36 - disabled: true - type: text - - name: status - value: Accepted - disabled: true - type: text - - name: step - value: Register - disabled: true - type: text - headers: - - name: Content-Type - value: multipart/form-data - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "" - name: Get details of step - meta: - id: req_b314a4c0bbdc469a932656553aacba20 - created: 1776615524771 - modified: 1776615524771 - isPrivate: false - description: "" - sortKey: -1776615518505 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: localhost:8078/v2/admin/kyc/history/626e9cef-c91e-4ba8-927e-5a186f4f14be - name: Get history of users' kyc level - meta: - id: req_c98ad332b4fc4f388ddcbc2040f32931 - created: 1776615524772 - modified: 1776615524772 - isPrivate: false - description: "" - sortKey: -1776615518504 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Config - meta: - id: fld_0660ffa98d1c4f1982dac2e16cd9958f - created: 1776615524773 - modified: 1776615524773 - sortKey: -1776615518503 - description: "" - children: - - url: "{{_['config-host']}}/user/v1" - name: Get user config - meta: - id: req_3e7d0bbe48284e93b76874668ff35887 - created: 1776615524774 - modified: 1776615524774 - isPrivate: false - description: "" - sortKey: -1776615518502 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/user/v1/pair" - name: Add pairs - meta: - id: req_8b5ffcb395984dfb9ddd7d80ff512085 - created: 1776615524775 - modified: 1776615524775 - isPrivate: false - description: "" - sortKey: -1776615518500 - method: POST - body: - mimeType: application/json - text: '["BTCUSDT", "ETHUSDT"]' - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/user/v1" - name: Update user config - meta: - id: req_bba0959e4dab418b919b2fa3e5c5d3e8 - created: 1776615524775 - modified: 1776615524775 - isPrivate: false - description: "" - sortKey: -1776615518501 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"theme\": \"dark\",\r - - \ \"language\": \"en\",\r - - \ \"favoritePairs\": [\"BTCUSDT\"]\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/user/v1/pair" - name: Remove pairs - meta: - id: req_f2637bc858b546ad8fc5d939c1794284 - created: 1776615524776 - modified: 1776615524776 - isPrivate: false - description: "" - sortKey: -1776615518499 - method: DELETE - body: - mimeType: application/json - text: '["ETHUSDT"]' - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/web/v1" - name: Get system config - meta: - id: req_846e2e5b249b49adbcdc6e851faa6d1d - created: 1776615524777 - modified: 1776615524777 - isPrivate: false - description: "" - sortKey: -1776615518498 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/web/v1" - name: Update system config - meta: - id: req_358c8c13d36d4dc0bb46b9bb52902a5b - created: 1776615524778 - modified: 1776615524778 - isPrivate: false - description: "" - sortKey: -1776615518497 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"logoUrl\": \"logo/url\",\r - - \ \"title\": \"Opex\",\r - - \ \"description\": \"Open Source Exchange\",\r - - \ \"defaultLanguage\": \"fa\",\r - - \ \"supportedLanguages\": [\"fa\",\"en\",\"uzb\"],\r - - \ \"defaultTheme\": \"DARK\",\r - - \ \"supportEmail\": \"hi@opex.co\",\r - - \ \"baseCurrency\": \"USDT\",\r - - \ \"dateType\": \"Jalali\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/web/v1" - name: Update system config Copy - meta: - id: req_4fdec1101afe4d6a80fc41d466f9b308 - created: 1776615524779 - modified: 1776615524779 - isPrivate: false - description: "" - sortKey: -1776615518496 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"logoUrl\": \"logo/url\",\r - - \ \"title\": \"Opex\",\r - - \ \"description\": \"Open Source Exchange\",\r - - \ \"defaultLanguage\": \"fa\",\r - - \ \"supportedLanguages\": [\"fa\",\"en\",\"uzb\"],\r - - \ \"defaultTheme\": \"DARK\",\r - - \ \"supportEmail\": \"hi@opex.co\",\r - - \ \"baseCurrency\": \"TUSDT\",\r - - \ \"dateType\": \"Jalali\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/user-level/v1" - name: Get user level config - meta: - id: req_23fdd438c5484375ac9f600f8c37a023 - created: 1776615524780 - modified: 1776615524780 - isPrivate: false - description: "" - sortKey: -1776615518495 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/user-level/v1" - name: Post/update user level config - meta: - id: req_b39dce4463cf4fc3939f1b72d62cfe76 - created: 1776615524781 - modified: 1776615524781 - isPrivate: false - description: "" - sortKey: -1776615518494 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"userLevel\": \"LEVEL_1\",\r - - \ \"name\": \"پایه\",\r - - \ \"description\": \"با تکمیل پروفایل و تایید اطلاعات - هویتی\",\r - - \ \"onChainDepositAllowed\": true,\r - - \ \"offChainDepositAllowed\": true,\r - - \ \"onChainWithdrawAllowed\": false,\r - - \ \"offChainWithdrawAllowed\": true\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['config-host']}}/user-level/v1/LEVEL_1" - name: Delete user level config - meta: - id: req_68f3b3fdaf9242d7af3d7320bc8e4127 - created: 1776615524782 - modified: 1776615524782 - isPrivate: false - description: "" - sortKey: -1776615518493 - method: DELETE - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Transaction history - meta: - id: fld_8116b719c79244f28ac3cdd39de45779 - created: 1776615524783 - modified: 1776615524783 - sortKey: -1776615518492 - description: "" - children: - - url: "{{_['market-host']}}/v1/user/tx/{{_['user-uuid']}}/history" - name: Buy and Sell - meta: - id: req_2fabdda11cba46849094e8f7d07a66fc - created: 1776615524783 - modified: 1776615524783 - isPrivate: false - description: "" - sortKey: -1776615518491 - method: POST - body: - mimeType: application/json - text: "\r - - \ { \"startTime\": null,\r - - \ \"endTime\": null,\r - - \ \"limit\": 200,\r - - \ \"offset\": 0,\r - - \ \"ascendingByTime\":false}" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/v1/deposit/history" - name: Deposit - meta: - id: req_47d5e3a47fdf468c8fad54fc8a81e5c1 - created: 1776615524784 - modified: 1776615524784 - isPrivate: false - description: "" - sortKey: -1776615518490 - method: POST - body: - mimeType: application/json - text: "{ // All fields are optional\r - - \ \"currency\": \"BTC\",\r - - \ \"startTime\": 1622505600,\r - - \ \"endTime\": 1625097600,\r - - \ \"limit\": 10,\r - - \ \"offset\": 0,\r - - \ \"ascendingByTime\": false\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/withdraw/history" - name: Withdraw - meta: - id: req_acbedb955494484e89e5c0151eafcc18 - created: 1776615524785 - modified: 1776615524785 - isPrivate: false - description: "" - sortKey: -1776615518489 - method: POST - body: - mimeType: application/json - text: "{ // All fields are optional\r - - \ \"currency\": \"BTC\",\r - - \ \"startTime\": 1622505600,\r - - \ \"endTime\": 1625097600,\r - - \ \"limit\": 10,\r - - \ \"offset\": 0,\r - - \ \"ascendingByTime\": false\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/v2/transaction" - name: Transaction history - meta: - id: req_c844afeb2b4543e8b5b99727274dd945 - created: 1776615524786 - modified: 1776615524786 - isPrivate: false - description: "" - sortKey: -1776615518488 - method: POST - body: - mimeType: application/json - text: "{ // All fields are optional\r - - \ \"currency\": \"BTC\",\r - - \ \"category\": \"TRADE\", // [TRADE, DEPOSIT, WITHDRAW, FEE, - SYSTEM]\r - - \ \"startTime\": 1622505600,\r - - \ \"endTime\": 1625097600,\r - - \ \"limit\": 10,\r - - \ \"offset\": 0,\r - - \ \"ascendingByTime\": false\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Referral - meta: - id: fld_72c6f326b84341e29cbca14024c5001a - created: 1776615524787 - modified: 1776615524787 - sortKey: -1776615518487 - description: "" - children: - - name: Code - meta: - id: fld_4a06a669d5834faf9dda5d4b2303599f - created: 1776615524787 - modified: 1776615524787 - sortKey: -1776615518486 - description: "" - children: - - url: "{{_['referral-host']}}/codes" - name: Generate Referral Code - meta: - id: req_9ccc1d593b8f4a9b985e8118f9de47b6 - created: 1776615524789 - modified: 1776615524789 - isPrivate: false - description: "" - sortKey: -1776615518485 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"uuid\" :\"1aac31a5-0443-44ed-aaf2-0022e85e1027\" ,\r - - \ \"commissionShare\" :\"STEP_4\" // STEP_1 , // STEP_2 - , // STEP_3 , // STEP_4\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['referral-host']}}/codes/10001" - name: Get Referral Code Info - meta: - id: req_b09fcabc2bb44982ae23377987f3ce2f - created: 1776615524790 - modified: 1776615524790 - isPrivate: false - description: "" - sortKey: -1776615518484 - method: GET - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['referral-host']}}/codes" - name: Get All Referral Codes - meta: - id: req_9fbea7ae46ad41f6b156cc6036349f8c - created: 1776615524791 - modified: 1776615524791 - isPrivate: false - description: "" - sortKey: -1776615518483 - method: GET - parameters: - - name: uuid - value: 1aac31a5-0443-44ed-aaf2-0022e85e1027 - disabled: false - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['referral-host']}}/codes/10002" - name: Delete Referral Code - meta: - id: req_fe971099a2a445bca28dee893928a18a - created: 1776615524792 - modified: 1776615524792 - isPrivate: false - description: "" - sortKey: -1776615518482 - method: DELETE - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Checkout - meta: - id: fld_f7a3fda72fd04d178c60583ddbe94d20 - created: 1776615524792 - modified: 1776615524792 - sortKey: -1776615518481 - description: "" - children: - - url: "{{_['referral-host']}}/checkouts/checkout-all" - name: Checkout All Rewards - meta: - id: req_881986a08a5f4be2b5e075f8d2ccdd92 - created: 1776615524793 - modified: 1776615524793 - isPrivate: false - description: "" - sortKey: -1776615518480 - method: POST - parameters: - - name: category - value: REFERRAL_COMMISSION - disabled: false - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['referral-host']}}/checkouts" - name: Get All Checkouts By Status - meta: - id: req_cb8efe4389594738aa87706f11bf63ea - created: 1776615524794 - modified: 1776615524794 - isPrivate: false - description: "" - sortKey: -1776615518479 - method: GET - parameters: - - name: status - value: CHECKED_OUT - disabled: false - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Config - meta: - id: fld_1e4e226b60454d9e91e73e377157b790 - created: 1776615524795 - modified: 1776615524795 - sortKey: -1776615518478 - description: "" - children: - - url: "{{_['referral-host']}}/configs" - name: Get Config - meta: - id: req_8dca19d89bce4506aa9ccb9d6d6aa0d6 - created: 1776615524797 - modified: 1776615524797 - isPrivate: false - description: "" - sortKey: -1776615518477 - method: GET - parameters: - - name: name - value: default - disabled: false - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Reference - meta: - id: fld_a047678c93734a8b9d14464b72bb680e - created: 1776615524798 - modified: 1776615524798 - sortKey: -1776615518476 - description: "" - children: - - url: "{{_['referral-host']}}/references/" - name: Get Referral Code's References - meta: - id: req_83719f86437c4972b3525b6219728c59 - created: 1776615524799 - modified: 1776615524799 - isPrivate: false - description: "" - sortKey: -1776615518474 - method: GET - parameters: - - name: uuid - value: 13cb32d1-f7f6-4d40-b33b-0d725fe3a2f4 - disabled: false - - name: code - value: "10000" - disabled: false - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['referral-host']}}/references/assign" - name: Assign Referrer - meta: - id: req_fb497dc8f2254bd88c9b03a0bfb93095 - created: 1776615524799 - modified: 1776615524799 - isPrivate: false - description: "" - sortKey: -1776615518475 - method: POST - parameters: - - name: uuid - value: 1aac31a5-0443-44ed-aaf2-0022e85e1027 - disabled: true - - name: code - value: "10000" - disabled: false - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Report - meta: - id: fld_28307ea76d5a428e8ba3924075e23fef - created: 1776615524800 - modified: 1776615524800 - sortKey: -1776615518473 - description: "" - children: - - url: "{{_['referral-host']}}/reports/1aac31a5-0443-44ed-aaf2-0022e85e1027" - name: Get Report By Uuid - meta: - id: req_e56863982cb24cf4bbca1cada0f9cf93 - created: 1776615524801 - modified: 1776615524801 - isPrivate: false - description: "" - sortKey: -1776615518472 - method: GET - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Reward - meta: - id: fld_f164894e6c654d96be729036bc5a0b97 - created: 1776615524802 - modified: 1776615524802 - sortKey: -1776615518471 - description: "" - children: - - url: "{{_['referral-host']}}/rewards" - name: Get Rewards - meta: - id: req_c52440fb93e34beb8d7ea67a1e30e9d4 - created: 1776615524803 - modified: 1776615524803 - isPrivate: false - description: "" - sortKey: -1776615518470 - method: GET - parameters: - - name: referentUuid - value: 1aac31a5-0443-44ed-aaf2-0022e85e1027 - disabled: true - - name: rewardedUuid - value: 13cb32d1-f7f6-4d40-b33b-0d725fe3a2f4 - disabled: false - - name: code - value: "10000" - disabled: true - authentication: - type: bearer - disabled: false - token: "" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Currency - meta: - id: fld_c01289d2912745f9a2c8bdfb58203707 - created: 1776615524803 - modified: 1776615524803 - sortKey: -1776615518469 - description: "" - children: - - url: "{{_['wallet-host']}}/currency" - name: Get Currencies List (with their gateways) - meta: - id: req_43a5115842784773b56510f01c763e38 - created: 1776615524817 - modified: 1776615524817 - isPrivate: false - description: "" - sortKey: -1776615518454 - method: GET - body: - mimeType: application/x-www-form-urlencoded - params: - - name: includeManualGateways - value: "true" - disabled: false - - name: includeOffChainGateways - value: "true" - disabled: false - - name: includeOnChainGateways - value: "true" - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/BTC" - name: Get Specific currency (with it's gateway) - meta: - id: req_a5cc0090b4b54aab8503fe1ff27a97ac - created: 1776615524818 - modified: 1776615524818 - isPrivate: false - description: "" - sortKey: -1776615518453 - method: GET - body: - mimeType: multipart/form-data - parameters: - - name: includeManualGateways - value: "true" - disabled: false - - name: includeOffChainGateways - value: "true" - disabled: false - - name: includeOnChainGateways - value: "true" - disabled: false - headers: - - name: Content-Type - value: multipart/form-data - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/IRT" - name: Update A Currency - meta: - id: req_ec235a66a3174017adb6ea3fff3b6f22 - created: 1776615524818 - modified: 1776615524818 - isPrivate: false - description: "" - sortKey: -1776615518452 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"symbol\": \"IRT\",\r - - \ \"uuid\": \"152a24a0-1d34-4149-996b-0bcd2c3a0c6a\",\r - - \ \"name\": \"Toman\",\r - - \ \"precision\": 0.0,\r - - \ \"title\": null,\r - - \ \"alias\": \"تومان\",\r - - \ \"icon\": - \"https://exky.io/storage/img/cryptocurrency-icons/irt.svg\",\r - - \ \"isTransitive\": false,\r - - \ \"isActive\": true,\r - - \ \"sign\": \"IRT\",\r - - \ \"description\": null,\r - - \ \"shortDescription\": null,\r - - \ \"withdrawAllowed\": false,\r - - \ \"depositAllowed\": false,\r - - \ \"externalUrl\": null,\r - - \ \"gateways\": null,\r - - \ \"availableGatewayType\": null,\r - - \ \"order\": 3,\r - - \ \"systemBalance\": null\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency" - name: Create New Currency - meta: - id: req_d0fe9e202a2b4be5a69856000b35fce4 - created: 1776615524819 - modified: 1776615524819 - isPrivate: false - description: "" - sortKey: -1776615518451 - method: POST - body: - mimeType: application/json - text: "\r - - \r - - {\"symbol\": \"IRT\",\r - - \"name\": \"Toman\",\r - - \"precision\": 0,\r - - \"title\": null,\r - - \"alias\": \"تومان\",\r - - \"icon\": - \"https://exky.io/storage/img/cryptocurrency-icons/irt.svg\",\r - - \"isTransitive\": false,\r - - \"isActive\": true,\r - - \"sign\": \"IRT\",\r - - \"description\": null,\r - - \"shortDescription\": null,\r - - \"externalUrl\": null,\r - - \"order\": 3,\r - - \"systemBalance\": 100000000\r - - \r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Gateways - meta: - id: fld_55e5ac1554b141be8ff802e9a520170f - created: 1776615524804 - modified: 1776615524804 - sortKey: -1776615518468 - description: "" - children: - - url: "{{ _['api-host'] }}/opex/v1/admin/IRT/gateway" - name: Create OffChain Gateway - meta: - id: req_08c3f75819e94c638c957f69e158511c - created: 1776615524805 - modified: 1778345831212 - isPrivate: false - description: "" - sortKey: -1776615518467 - method: POST - body: - mimeType: application/json - text: |- - { - "type": "OffChain", - "currencySymbol":"IRT", - "depositMin": 50000, - "depositMax": 10000000, - "withdrawMin": 50000, - "withdrawMax": 10000000, - "withdrawFee": 10000, - "withdrawAllowed": true, - "depositAllowed": true, - "isDepositActive": true, - "isWithdrawActive": true, - "transferMethod": "SHEBA" - } - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['bc-gateway-host']}}/crypto-currency/gateways" - name: Get All Gateways - meta: - id: req_676a3ce67e604c4d93443e0ae396380d - created: 1776615524806 - modified: 1778327934979 - isPrivate: false - description: "" - sortKey: -1776615518466 - method: GET - body: - mimeType: multipart/form-data - params: - - name: includeOnChainGateways - value: "true" - disabled: false - type: text - - name: includeOffChainGateways - value: "true" - disabled: false - type: text - - name: includeManualGateways - value: "false" - disabled: false - type: text - headers: - - name: Accept-Language - value: FA - - name: Content-Type - value: multipart/form-data - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/DOGE/gateway/ofg_2b2fac37-38c1-49b9-b75a-b4\ - e596e29cc7" - name: Update The Gateway - meta: - id: req_d99a3e07a96e4ff0bfc123696cdc9e8f - created: 1776615524807 - modified: 1776615524807 - isPrivate: false - description: "" - sortKey: -1776615518465 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"type\": \"OffChain\",\r - - \ \"transferMethod\": \"VOUCHER\",\r - - \ \"currencySymbol\": \"USDT\",\r - - \ \"isDepositActive\": true,\r - - \ \"isWithdrawActive\": true,\r - - \ \"withdrawFee\": 0.1,\r - - \ \"withdrawAllowed\": false,\r - - \ \"depositAllowed\": true,\r - - \ \"depositMin\": 1,\r - - \ \"depositMax\": 50,\r - - \ \"withdrawMin\": 2,\r - - \ \"withdrawMax\": 10,\r - - \ \"depositDescription\": null,\r - - \ \"withdrawDescription\": null,\r - - \ \"displayOrder\": 3\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/IRT/gateway/ofg_b2ae229e-3387-4d71-abe9-d82\ - ed8500b02" - name: Delete The Gateway - meta: - id: req_42cf4905486b4bfea2946f9a9e706a80 - created: 1776615524808 - modified: 1776615524808 - isPrivate: false - description: "" - sortKey: -1776615518464 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/gateway/ofg_c471822f-0f22-42e6-ab57-a4dd056\ - 43e6f/terminal" - name: Assign terminal to a gateway - meta: - id: req_d6021dc715b548a68cf5602db667ea78 - created: 1776615524808 - modified: 1776615524808 - isPrivate: false - description: "" - sortKey: -1776615518463 - method: POST - body: - mimeType: application/json - text: '["4c84512d-901e-4575-bd7e-f68e8c66e137"]' - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/gateway/ofg_c471822f-0f22-42e6-ab57-a4dd056\ - 43e6f/terminal" - name: Delete gateway's terminal - meta: - id: req_58870d4a7900404791695ed23e4b340c - created: 1776615524809 - modified: 1776615524809 - isPrivate: false - description: "" - sortKey: -1776615518462 - method: DELETE - body: - mimeType: application/json - text: '["ac4029d1-ed4c-4430-a3ed-788bef525880"]' - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/gateway/ofg_c471822f-0f22-42e6-ab57-a4dd056\ - 43e6f/terminal" - name: Get gateway's terminal - meta: - id: req_74651f24239e4d8f8c5c276626c44b39 - created: 1776615524810 - modified: 1776615524810 - isPrivate: false - description: "" - sortKey: -1776615518461 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/IRT/gateway/ofg_2adf97d0-06c2-4528-9f04-396\ - dcce301be" - name: Update The Gateway - DepositDes - meta: - id: req_c16f3a2baba04ab1b54035f360a3a58c - created: 1776615524811 - modified: 1776615524811 - isPrivate: false - description: "" - sortKey: -1776615518460 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"type\": \"OffChain\",\r - - \ \"depositMin\": 10000,\r - - \ \"depositMax\": 50000000,\r - - \ \"withdrawMin\": 10000,\r - - \ \"withdrawMax\": 50000000,\r - - \ \"isDepositActive\": true,\r - - \ \"isWithdrawActive\": false,\r - - \ \"withdrawFee\": 10000,\r - - \ \"withdrawAllowed\": true,\r - - \ \"depositAllowed\": true,\r - - \ \"transferMethod\": \"SHEBA\",\r - - \ \"displayOrder\": 2,\r - - \ \"depositDescription\": \"پس از انتخاب بانک مقصد و شماره - شبای نمایش‌داده‌شده، مبلغ موردنظر را «فقط از حسابی به نام - خودتان» با روش انتقال وجه از طریق شبا و با ثبت «شناسه واریز» - درج‌شده انتقال دهید.\\n\\n- حساب مبدا حتماً باید به نام - خودتان باشد؛ در غیر این صورت مبلغ واریز شده به حساب مبدا - عودت داده خواهد شد.\\n- در صورت عدم ثبت یا ثبت اشتباه شناسه - واریز، مبلغ به حساب شما نخواهد نشست. پیگیری آن در اوپکس - مقدور نیست و نهایتاً تا ۷۲ ساعت به حساب مبدا - بازمی‌گردد.\",\r - - \ \"withdrawDescription\": null\r - - }\r\n" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/currency/IRT/gateway" - name: Create Onchain Gateway - meta: - id: req_a2fc6437a7c5458daa6f3cdc7160f46b - created: 1778083502093 - modified: 1778345259535 - isPrivate: false - description: "" - sortKey: -1776615518466.5 - method: POST - body: - mimeType: application/json - text: |- - { - "type": "OnChain", - "implementationSymbol":"irt", - "depositMin": 50000, - "depositMax": 10000000, - "withdrawMin": 50000, - "withdrawMax": 10000000, - "isActive": true, - "withdrawFee": 10000, - "withdrawAllowed": true, - "depositAllowed": true, - "isDepositActive": true, - "isWithdrawActive": true, - "decimal":2, - "chain":"btc" - } - headers: - - name: Content-Type - value: application/json - - name: "Authorization " - value: Bearer - eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0TE5KVE44SnJjdmM1Nno3ZklocUVwZnJWUEhFNlJvdDZ5V2VXN3JMNXpBIn0.eyJleHAiOjE3NzgwODYwNDcsImlhdCI6MTc3ODA4NTQ0NywianRpIjoiMDdlY2M5NTAtNTc3ZC00ZmQzLWJhZDctMzZhMWU0Y2UxMmQ2IiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJzdWIiOiI5ZjNlOTQ4MC05MWY3LTQ5YjEtOTA1Zi03ZGRkMThhYWMzMDEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiZmFlYjdhNDAtYzNkYi00OTY1LWE5NTctZWVkNzE4ODMzOWJlIiwic2NvcGUiOiJ0cnVzdCIsInBlcm1pc3Npb25zIjpbImRlcG9zaXQ6d3JpdGUiLCJvcmRlcjp3cml0ZSIsImFkZHJlc3M6YXNzaWduIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiIsImRlcG9zaXQ6d3JpdGUiLCJ3aXRoZHJhdzp3cml0ZSIsInZvdWNoZXI6c3VibWl0IiwiYmFua19hY2NvdW50OndyaXRlIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJzdXBlci1hZG1pbiIsImRlZmF1bHQtcm9sZXMtb3BleCIsImFkbWluIiwidXNlci0yIiwidXNlciJdLCJlbWFpbCI6ImFkbWluQG9wZXguZGV2IiwidXNlcm5hbWUiOiJhZG1pbiJ9.Z6tQXcIRJjlTMCeDecSL7WMDGG0gpzsvX9okGrjcTDVT-g26vJI_JaLf-epf-z1mzKHtxj4GvD4NjCQeDwayawF1AEQC1tmr3XFd5ddDzPmBKozG7iWvB5u_-ikX2WZHTn4PsjuUSeZRAjytu5CyCHSJrTvURj2yXpkmXDXIsZZzBTRhx2UAN0cAjNlZ5-r0PwRI4B0sc6sC8kW7fVuFVjtzCwm062DlpSg6IoFY_UUQNhrOeCPObBTuWx7zM_N_7kqRxsFeLqQ-tjkqonMkgUZeT8vcoMzxGGJ4-bLoRazS3rINJglpTudQ2NxZVFBfAiWT2jKODIyvLj8r3ETHDQ - description: "" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{ _['super-admin-token'] }}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: terminal - meta: - id: fld_5f82d453447d4e2fb00528c5b4fdb775 - created: 1776615524811 - modified: 1776615524811 - sortKey: -1776615518459 - description: "" - children: - - url: "{{_['wallet-host']}}/admin/deposit/terminal" - name: Create - meta: - id: req_a202dd777a2b48499451236d81481163 - created: 1776615524813 - modified: 1776615524813 - isPrivate: false - description: "" - sortKey: -1776615518458 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"owner\": \"سامان\",\r - - \ \"identifier\": \" \",\r - - \ \"active\": true,\r - - \ \"type\": \"IPG\", //CARD , SHEBA , IPG , EXCHANGE \r - - \ \"metaData\": \"saman\",\r - - \ \"description\" : \"\" //optional\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/deposit/terminal/4c84512d-901e-4575-bd7e-f68e8\ - c66e137" - name: Update - meta: - id: req_32797b283f9041bab6172787454b7171 - created: 1776615524814 - modified: 1776615524814 - isPrivate: false - description: "" - sortKey: -1776615518457 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"owner\": \"آسان پرداخت\",\r - - \ \"identifier\": \" \",\r - - \ \"active\": true,\r - - \ \"type\": \"IPG\", //CARD , SHEBA , IPG , EXCHANGE \r - - \ \"metaData\": \"sadad\",\r - - \ \"description\" : \"\" //optional\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['base-url-wallet']}}/admin/deposit/terminal/ac4029d1-ed4c-4430-a3ed-7\ - 88bef525880" - name: Delete - meta: - id: req_8e79b54b17d240b0a267545c504e7f1b - created: 1776615524815 - modified: 1776615524815 - isPrivate: false - description: "" - sortKey: -1776615518456 - method: DELETE - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/deposit/terminal" - name: Get - meta: - id: req_c7a9426cab4e4f70941be326a360e889 - created: 1776615524816 - modified: 1776615524816 - isPrivate: false - description: "" - sortKey: -1776615518455 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Voucher - meta: - id: fld_b55ac1270a8b4753b5afe7b694d8a214 - created: 1776615524820 - modified: 1776615524820 - sortKey: -1776615518450 - description: "" - children: - - url: "{{_['wallet-host']}}/admin/voucher/dr-1234567890" - name: Get Voucher Data - meta: - id: req_bff7f68f7c644945a492dfd5c75c624c - created: 1776615524821 - modified: 1776615524821 - isPrivate: false - description: "" - sortKey: -1776615518449 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/admin/voucher" - name: Get Vouchers Data - meta: - id: req_48b94b54818d4968a952fb60bec86a16 - created: 1776615524822 - modified: 1776615524822 - isPrivate: false - description: "" - sortKey: -1776615518448 - method: GET - parameters: - - name: isUsed - value: "true" - disabled: false - - name: type - value: SALE - disabled: false - - name: issuer - value: Nilin - disabled: true - - name: limit - value: "10" - disabled: true - - name: | - offset - value: "0" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/voucher/afce5c6dbcb64c63" - name: Submit Voucher - meta: - id: req_916120fbfca44f29bf63aa0fe17e1051 - created: 1776615524823 - modified: 1776615524823 - isPrivate: false - description: "" - sortKey: -1776615518447 - method: PUT - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: | - {{_['wallet-host']}}/admin/voucher/sell/DST-1025 - name: Get Sell Voucher Data - meta: - id: req_2eda3a5738754a16998b56ab8e211a7c - created: 1776615524824 - modified: 1776615524824 - isPrivate: false - description: "" - sortKey: -1776615518446 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: | - {{_['wallet-host']}}/admin/voucher/sell - name: Sell Voucher - meta: - id: req_2d54b817b22b4c6a86e267fc73229db8 - created: 1776615524825 - modified: 1776615524825 - isPrivate: false - description: "" - sortKey: -1776615518445 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"publicCode\" : \"DST-1000\",\r - - \ \"nationalCode\": \"1234567890\",\r - - \ \"phoneNumber\" : \"09981390909\",\r - - \ \"transactionNumber\" : \"1987654321\",\r - - \ \"transactionAmount\" : \"100000\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: chain - meta: - id: fld_964414e8723e496e8389078db4e30156 - created: 1776615524825 - modified: 1776615524825 - sortKey: -1776615518444 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/market/chain" - name: chains - meta: - id: req_713dd43a20674e11a717ad0f7c2854e2 - created: 1776615524826 - modified: 1776615524826 - isPrivate: false - description: "" - sortKey: -1776615518443 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: otp - meta: - id: fld_4c4fc1fd81124dbebadd00409cf3d218 - created: 1776615524827 - modified: 1776615524827 - sortKey: -1776615518442 - description: "" - children: - - url: http://localhost:8097/v1/otp - name: Request otp - meta: - id: req_4fa7692664ef4550bb08ecd005cfdbf3 - created: 1776615524827 - modified: 1776615524827 - isPrivate: false - description: "" - sortKey: -1776615518441 - method: POST - body: - mimeType: application/json - text: |- - [ - { - "receiver": "09383381451", - "type": "SMS" - }, - { - "receiver": "email@opex.dev", - "type": "EMAIL" - } - ] - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8097/v1/otp/verify/59816858-0544-4e84-9b89-6db2cb4694eb - name: verify otp - meta: - id: req_492d676d54c344a589653a31f4f3fcc5 - created: 1776615524829 - modified: 1776615524829 - isPrivate: false - description: "" - sortKey: -1776615518440 - method: POST - body: - mimeType: application/json - text: |- - [ - { - "code": "796229", - "type": "SMS" - }, - { - "code": "KqpAKxXh", - "type": "EMAIL" - } - ] - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8097/v1/totp/setup - name: Setup totp - meta: - id: req_f08aa5379bb04bc2ac2648e2cda4907c - created: 1776615524830 - modified: 1776615524830 - isPrivate: false - description: "" - sortKey: -1776615518439 - method: POST - body: - mimeType: application/json - text: |- - { - "userId": "1234", - "label": "a@a.c" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8097/v1/totp/setup/verify - name: Verify setup totp - meta: - id: req_e3dd8f815de1428094cee545872b0448 - created: 1776615524831 - modified: 1776615524831 - isPrivate: false - description: "" - sortKey: -1776615518438 - method: POST - body: - mimeType: application/json - text: |- - { - "userId": "1234", - "code": "395491" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8097/v1/totp/verify - name: Verify totp - meta: - id: req_a3b9f6d3a0344049918ff5a50f8ddd76 - created: 1776615524832 - modified: 1776615524832 - isPrivate: false - description: "" - sortKey: -1776615518437 - method: POST - body: - mimeType: application/json - text: |- - { - "userId": "1234", - "code": "940557" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: http://localhost:8097/v1/totp - name: Delete totp - meta: - id: req_0a813b34a95149ce9715706d7690dcf7 - created: 1776615524833 - modified: 1776615524833 - isPrivate: false - description: "" - sortKey: -1776615518436 - method: DELETE - body: - mimeType: application/json - text: |- - { - "userId": "1234", - "code": "124690" - } - headers: - - name: Content-Type - value: application/json - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: New UI Services - meta: - id: fld_75d79988593b49bc824f075a407a664b - created: 1776615524833 - modified: 1776615524833 - sortKey: -1776615518435 - description: "" - children: - - url: "" - name: Get users detail assets - meta: - id: req_aea3f8a952ba4724bc6ed909475b6d8c - created: 1776615524885 - modified: 1776615524885 - isPrivate: false - description: "" - sortKey: -1776615518382 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: History and Summary - meta: - id: fld_6e851fbe4b5b4d11a1dab8b07d24de6b - created: 1776615524834 - modified: 1776615524834 - sortKey: -1776615518434 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/user/history/order/count" - name: Get user order history count - meta: - id: req_1bc4934d616e4a13b99cb5577d4cdb36 - created: 1776615524835 - modified: 1776615524835 - isPrivate: false - description: "" - sortKey: -1776615518432 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: true - - name: orderType - value: LIMIT_ORDER - disabled: true - - name: direction - value: ASK - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/order" - name: Get user order history - meta: - id: req_2513c1b73b4c414a87fa322ba0ed10a8 - created: 1776615524835 - modified: 1776615524835 - isPrivate: false - description: "" - sortKey: -1776615518433 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: true - - name: orderType - value: LIMIT_ORDER - disabled: true - - name: direction - value: ASK - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - - name: limit - value: "1" - disabled: true - - name: offset - value: "0" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/trade" - name: Get user trade history - meta: - id: req_9151e46c1926430a8887e8db93db5739 - created: 1776615524837 - modified: 1776615524837 - isPrivate: false - description: "" - sortKey: -1776615518431 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: true - - name: direction - value: ASK - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - - name: limit - value: "1" - disabled: true - - name: offset - value: "0" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/trade/count" - name: Get user trade history count - meta: - id: req_5eb30e919f344ec9a66230256efa72e7 - created: 1776615524838 - modified: 1776615524838 - isPrivate: false - description: "" - sortKey: -1776615518430 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: true - - name: direction - value: ASK - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/withdraw" - name: Get user withdraw history - meta: - id: req_f977a6d8c10c4debb7ace25826a0a549 - created: 1776615524838 - modified: 1776615524838 - isPrivate: false - description: "" - sortKey: -1776615518429 - method: GET - parameters: - - name: currency - value: BTC - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - - name: limit - value: "1" - disabled: true - - name: offset - value: "0" - disabled: true - - name: ascendingByTime - value: "true" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/withdraw/count" - name: Get user withdraw history count - meta: - id: req_9f349c8641644c25aacd431e0a1dd126 - created: 1776615524839 - modified: 1776615524839 - isPrivate: false - description: "" - sortKey: -1776615518428 - method: GET - parameters: - - name: currency - value: BTC_USDT - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/summary/trade" - name: Get user trade summary - meta: - id: req_9d8cb3667d5547d6b1286d37ba22e1ac - created: 1776615524840 - modified: 1776615524840 - isPrivate: false - description: "" - sortKey: -1776615518427 - method: GET - parameters: - - name: limit - value: "10" - disabled: false - - name: startTime - value: "1" - disabled: false - - name: endTime - value: "1745267400000" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/summary/deposit" - name: Get user deposit summary - meta: - id: req_1cb8a878914647bba06f8926d2856a2a - created: 1776615524841 - modified: 1776615524841 - isPrivate: false - description: "" - sortKey: -1776615518426 - method: GET - parameters: - - name: limit - value: "10" - disabled: false - - name: startTime - value: "1745181000000" - disabled: false - - name: endTime - value: "1745267400000" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/summary/withdraw" - name: Get user withdraw summary - meta: - id: req_db76f5b96b974d8f8ef04a81803f18f9 - created: 1776615524842 - modified: 1776615524842 - isPrivate: false - description: "" - sortKey: -1776615518425 - method: GET - parameters: - - name: limit - value: "10" - disabled: false - - name: startTime - value: "1" - disabled: false - - name: endTime - value: "1745267400000" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/deposit/count" - name: Get user deposit history count - meta: - id: req_88dd5d44c0104defb80c57f35c132fdd - created: 1776615524843 - modified: 1776615524843 - isPrivate: false - description: "" - sortKey: -1776615518423 - method: GET - parameters: - - name: currency - value: BTC_USDT - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/deposit" - name: Get user deposit history - meta: - id: req_a47aa34e0d6f4b5f9f40dcc929411de9 - created: 1776615524843 - modified: 1776615524843 - isPrivate: false - description: "" - sortKey: -1776615518424 - method: GET - parameters: - - name: currency - value: BTC - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - - name: limit - value: "1" - disabled: true - - name: offset - value: "0" - disabled: true - - name: ascendingByTime - value: "true" - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/transaction" - name: Get user transaction history - meta: - id: req_8a81a6e5d5c0427c8d3d7390eb3b81df - created: 1776615524845 - modified: 1776615524845 - isPrivate: false - description: "" - sortKey: -1776615518422 - method: GET - parameters: - - name: currency - value: BTC - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - - name: limit - value: "1" - disabled: true - - name: offset - value: "0" - disabled: true - - name: ascendingByTime - value: "true" - disabled: true - - name: category - value: TRADE - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/transaction/count" - name: Get user transaction history count - meta: - id: req_b8b9166dc5f745e7b33e35772ba1710a - created: 1776615524846 - modified: 1776615524846 - isPrivate: false - description: "" - sortKey: -1776615518421 - method: GET - parameters: - - name: currency - value: BTC_USDT - disabled: true - - name: startTime - value: "1716437636490" - disabled: true - - name: endTime - value: "1746437636490" - disabled: true - - name: category - value: TRADE - disabled: true - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/swap" - name: Get user swap history - meta: - id: req_d527d8b11e9b4475ad6805ef81e5ea3f - created: 1776615524847 - modified: 1776615524847 - isPrivate: false - description: "" - sortKey: -1776615518420 - method: POST - body: - mimeType: application/json - text: "{\r - - \ // sourceSymbol\r - - \ // destSymbol\r - - \ // startTime\r - - \ // endTime\r - - \ // limit (default 10)\r - - \ // offset (default 0)\r - - \ // ascendingByTime (default false)\r - - \r - - \ // ** All Optional **\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/history/swap/count" - name: Get user swap history count - meta: - id: req_52938c4c01454d9194f429fa13721c5e - created: 1776615524848 - modified: 1776615524848 - isPrivate: false - description: "" - sortKey: -1776615518419 - method: POST - body: - mimeType: application/json - text: "{\r - - \ // sourceSymbol\r - - \ // destSymbol\r - - \ // startTime\r - - \ // endTime\r - - \r - - \ // ** All Optional **\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Wallet - meta: - id: fld_1bb957d952a8427baa3f17cab05b8e6e - created: 1776615524849 - modified: 1776615524849 - sortKey: -1776615518418 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/wallet/asset" - name: Get User Wallet Asset - meta: - id: req_cfdc366084ed45818cf641d2c87b76b7 - created: 1776615524857 - modified: 1776615524857 - isPrivate: false - description: "" - sortKey: -1776615518409 - method: GET - parameters: - - name: symbol - value: BTC - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Withdraw - meta: - id: fld_9357a5de127344c2be8f0b3229bb4abf - created: 1776615524849 - modified: 1776615524849 - sortKey: -1776615518417 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/withdraw" - name: Request withdraw - meta: - id: req_a71a73e511a34bb0bacad1b167084e3a - created: 1776615524850 - modified: 1776615524850 - isPrivate: false - description: "" - sortKey: -1776615518416 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"currency\": \"IRT\",\r - - \ \"amount\": 100,\r - - // \"destSymbol\": \"USDT\",\r - - \ \"destAddress\": - \"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa\",\r - - // \"destNetwork\": \"test-ethereum\",\r - - \ \"destNote\": \"Personal wallet\", //Optional\r - - \ \"description\": \"Withdrawal to personal wallet\" - ,//Optional\r - - \ - \"gatewayUuid\":\"ofg_0843c1f0-a35d-4ead-a427-9c262924f\ - 9f7\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/withdraw/5/cancel" - name: Cancel withdraw - meta: - id: req_0a78f954fc464ec99c7bc784376e6bbc - created: 1776615524851 - modified: 1776615524851 - isPrivate: false - description: "" - sortKey: -1776615518415 - method: PUT - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/withdraw/5" - name: Get withdraw - meta: - id: req_f4d005d7419b4069aca18a24e357b86c - created: 1776615524852 - modified: 1776615524852 - isPrivate: false - description: "" - sortKey: -1776615518414 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/withdraw/78/otp/EMAIL/request" - name: Request OTP - meta: - id: req_a9f03524774e4a5d8b33c6ec918298f6 - created: 1776615524853 - modified: 1776615524853 - isPrivate: false - description: "" - sortKey: -1776615518413 - method: POST - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/withdraw/78/otp/EMAIL/verify" - name: Verify OTP - meta: - id: req_01c7fb7c94b449f6bd40231f12b30919 - created: 1776615524854 - modified: 1776615524854 - isPrivate: false - description: "" - sortKey: -1776615518412 - method: POST - parameters: - - name: otpCode - value: a123d22 - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Deposit - meta: - id: fld_7a0b380889164252aebc08de86a43da0 - created: 1776615524855 - modified: 1776615524855 - sortKey: -1776615518411 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/deposit" - name: Deposit - meta: - id: req_2b063833a5504a4490437a7da60803d1 - created: 1776615524856 - modified: 1776615524856 - isPrivate: false - description: "" - sortKey: -1776615518410 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"symbol\" :\"BTC\",\r - - \ \"receiverUuid\" :\"1\",\r - - \ \"receiverWalletType\" :\"MAIN\",\r - - \ \"amount\" :123,\r - - \ \"description\" : \"\",\r - - \ \"transferRef\" : \"\",\r - - \ \"gatewayUuid\" : \"\",\r - - \ \"chain\" : \"\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Exchange info - meta: - id: fld_cf0bf387d3e4412681b24ffc82190aa8 - created: 1776615524857 - modified: 1776615524857 - sortKey: -1776615518408 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/market/fee" - name: Get fee levels - meta: - id: req_41d18e51c0d44a58b3c989a2838d6c09 - created: 1776615524858 - modified: 1776615524858 - isPrivate: false - description: "" - sortKey: -1776615518407 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/pair" - name: Get pair info - meta: - id: req_58b5d353da2b4e03a982e87410435d7f - created: 1776615524859 - modified: 1776615524859 - isPrivate: false - description: "" - sortKey: -1776615518406 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/currency" - name: Get currency - meta: - id: req_1a9d36ef7afa4d6a8763383d6a652904 - created: 1776615524860 - modified: 1776615524860 - isPrivate: false - description: "" - sortKey: -1776615518405 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/currency/gateway" - name: Get gateway - meta: - id: req_b0aa36bdb6b84d2789866e30450851e7 - created: 1776615524861 - modified: 1776615524861 - isPrivate: false - description: "" - sortKey: -1776615518404 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/stats" - name: Get market stats - meta: - id: req_9e9793903fcf4fc68fc9bab623a23f4e - created: 1776615524862 - modified: 1776615524862 - isPrivate: false - description: "" - sortKey: -1776615518403 - method: GET - parameters: - - name: interval - value: 7d - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/info" - name: Get market info - meta: - id: req_ed4f0fa65c1d4edeafa3db82a11fdfd9 - created: 1776615524863 - modified: 1776615524863 - isPrivate: false - description: "" - sortKey: -1776615518402 - method: GET - parameters: - - name: interval - value: 1Y - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/ticker/1M" - name: Get price change - meta: - id: req_ae511914d0ab44f5a747e59ee9446f63 - created: 1776615524864 - modified: 1776615524864 - isPrivate: false - description: "" - sortKey: -1776615518401 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/ticker/price" - name: Get price ticker - meta: - id: req_585149b3dfd84327b96c8835e9102716 - created: 1776615524865 - modified: 1776615524865 - isPrivate: false - description: "" - sortKey: -1776615518400 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/currencyInfo/quotes" - name: Get quote currencies - meta: - id: req_672e7c4bfe93415684836c4856be6b6a - created: 1776615524865 - modified: 1776615524865 - isPrivate: false - description: "" - sortKey: -1776615518399 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/klines" - name: Get klines - meta: - id: req_520475cb798840a783d4beb0c7f2af7b - created: 1776615524866 - modified: 1776615524866 - isPrivate: false - description: "" - sortKey: -1776615518398 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: false - - name: interval - value: 1M - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/basic-data" - name: Get basic data - meta: - id: req_d9411af2df4844a79da8219653aebd0f - created: 1776615524867 - modified: 1776615524867 - isPrivate: false - description: "" - sortKey: -1776615518397 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/market/withdraw-limits" - name: Get withdraw limits - meta: - id: req_325500825f1a4b90bdeb99af272a7418 - created: 1776615524868 - modified: 1776615524868 - isPrivate: false - description: "" - sortKey: -1776615518396 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Order - meta: - id: fld_7201162a1e0949de83acb1a7b8904670 - created: 1776615524869 - modified: 1776615524869 - sortKey: -1776615518395 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/market/depth" - name: Get order book - meta: - id: req_500f9bba8eb54f2a9c652d288f672fdc - created: 1776615524870 - modified: 1776615524870 - isPrivate: false - description: "" - sortKey: -1776615518394 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/order" - name: Create order - meta: - id: req_f325022865d947348ec26b218fb01b92 - created: 1776615524871 - modified: 1776615524871 - isPrivate: false - description: "" - sortKey: -1776615518393 - method: POST - parameters: - - name: symbol - value: BTC_USDT - disabled: false - - name: side - value: SELL - disabled: false - - name: type - value: LIMIT - disabled: false - - name: timeInForce - value: GTC - disabled: false - - name: timestamp - value: "1626805452" - disabled: false - - name: quantity - value: "0.1" - disabled: false - - name: price - value: "100500" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/order" - name: Get order - meta: - id: req_a7e777b3b45b442982a0c43df50c9628 - created: 1776615524872 - modified: 1776615524872 - isPrivate: false - description: "" - sortKey: -1776615518392 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: false - - name: orderId - value: "37" - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/order" - name: Cancel order - meta: - id: req_0b2e2da258434d00bf552eccb7e6f6c5 - created: 1776615524873 - modified: 1776615524873 - isPrivate: false - description: "" - sortKey: -1776615518391 - method: PUT - parameters: - - name: symbol - value: BTC_USDT - disabled: false - - name: orderId - value: "37" - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/order/open" - name: Get Open Orders - meta: - id: req_9001ec86cb81425da7070d4f5b0bcb87 - created: 1776615524874 - modified: 1776615524874 - isPrivate: false - description: "" - sortKey: -1776615518390 - method: GET - parameters: - - name: symbol - value: BTC_USDT - disabled: false - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Voucher - meta: - id: fld_6590767246ea4d828edb032c1f7e8ce4 - created: 1776615524875 - modified: 1776615524875 - sortKey: -1776615518389 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/voucher/CJB51X" - name: Submit voucher - meta: - id: req_b5c0b8c4a7204b64b1a4651054cd4a01 - created: 1776615524875 - modified: 1776615524875 - isPrivate: false - description: "" - sortKey: -1776615518388 - method: PUT - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: User - meta: - id: fld_d1812777d63c4970b31f17a3bfaad8e6 - created: 1776615524877 - modified: 1776615524877 - sortKey: -1776615518387 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/user/data/trade/volume/total" - name: Get total trade volume value - meta: - id: req_d2719cafb1a645e583333a2625daa414 - created: 1776615524878 - modified: 1776615524878 - isPrivate: false - description: "" - sortKey: -1776615518386 - method: GET - parameters: - - name: interval - value: Month - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/data/trade/volume" - name: Get total trade volume by symbol - meta: - id: req_aae9309e73db4e79888755e54e90776b - created: 1776615524880 - modified: 1776615524880 - isPrivate: false - description: "" - sortKey: -1776615518385 - method: GET - parameters: - - name: interval - value: Day - disabled: false - - name: symbol - value: BTC - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/data/fee" - name: Get user fee level - meta: - id: req_1eec675a660843a590c7f6b0795226b4 - created: 1776615524882 - modified: 1776615524882 - isPrivate: false - description: "" - sortKey: -1776615518384 - method: GET - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['api-host']}}/opex/v1/user/data/withdraw/volume/total" - name: Get User withdraw volume - meta: - id: req_3ddaa7d90a6447629c29e75992f667e5 - created: 1776615524882 - modified: 1776615524882 - isPrivate: false - description: "" - sortKey: -1776615518383 - method: GET - parameters: - - name: interval - value: 1w - disabled: true - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Messages - meta: - id: fld_2c774d8e716546e9b34751d568eb9be1 - created: 1776615524886 - modified: 1776615524886 - sortKey: -1776615518381 - description: "" - children: - - url: "{{host}}/config/messages" - name: Search for messages - meta: - id: req_a24c6fdb68be450798ada93177d82a4e - created: 1776615524887 - modified: 1776615524887 - isPrivate: false - description: "" - sortKey: -1776615518380 - method: GET - parameters: - - name: key - value: tg - disabled: true - - name: message - value: tg - disabled: true - - name: category - value: "" - disabled: true - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{host}}/config/messages" - name: Create or update a message - meta: - id: req_ab1cdc90b6c94ed08f31bcb7ac53ec9c - created: 1776615524888 - modified: 1776615524888 - isPrivate: false - description: "" - sortKey: -1776615518379 - method: POST - body: - mimeType: application/json - text: "{\r - - \ \"key\": \"USDT\",\r - - \ \"userLanguage\": \"EN\",\r - - \ \"message\": \"TETHERRR\",\r - - \ \"category\":\"ERROR_CODE\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{host}}/config/messages" - name: Delete - meta: - id: req_1099e3e64865453cb9ca2f16280f9602 - created: 1776615524889 - modified: 1776615524889 - isPrivate: false - description: "" - sortKey: -1776615518378 - method: DELETE - body: - mimeType: application/json - text: "{\r - - \ \"key\": \"USDT\",\r - - \ \"userLanguage\": \"EN\",\r - - \ \"category\": \"ERROR_CODE\"\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Otc - meta: - id: fld_305d29001c834414b88e6abd5450c9d9 - created: 1776615524890 - modified: 1776615524890 - sortKey: -1776615518377 - description: "" - children: - - url: "{{_['wallet-host']}}/otc/route" - name: Get route - meta: - id: req_2f606fd85e9348e4ae42f9f2c34e5393 - created: 1776615524891 - modified: 1776615524891 - isPrivate: false - description: "" - sortKey: -1776615518376 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/otc/rate" - name: Get rate - meta: - id: req_8b2314eb77f548f192ba9b7f638e9264 - created: 1776615524891 - modified: 1776615524891 - isPrivate: false - description: "" - sortKey: -1776615518375 - method: GET - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/otc/rate" - name: Add rate - meta: - id: req_355fb2d91e2f48538539b62950ad86a8 - created: 1776615524892 - modified: 1776615524892 - isPrivate: false - description: "" - sortKey: -1776615518374 - method: POST - body: - mimeType: application/json - text: |- - { - "sourceSymbol": "BNB", - "destSymbol": "IRT", - "rate": 53208905.1092900039676578671 - } - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/otc/rate" - name: Update rate - meta: - id: req_5c58c7a7bcd24390aa03bc02850983cc - created: 1776615524894 - modified: 1776615524894 - isPrivate: false - description: "" - sortKey: -1776615518372 - method: PUT - body: - mimeType: application/json - text: "{\r - - \ \"sourceSymbol\": \"USDT\",\r - - \ \"destSymbol\": \"IRT\",\r - - \ \"rate\": 98.25\r - - }" - headers: - - name: Content-Type - value: application/json - authentication: - type: bearer - disabled: false - token: "{{_['super-admin-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: "{{_['wallet-host']}}/otc/currency/price" - name: Get currency price - meta: - id: req_a918a366b7d448e1876fcaa2f9d9b70e - created: 1776615524894 - modified: 1776615524894 - isPrivate: false - description: "" - sortKey: -1776615518373 - method: GET - body: - mimeType: application/x-www-form-urlencoded - params: - - name: unit - value: USDT - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: bc-gateway - meta: - id: fld_806840601011492694d079ca19d0726f - created: 1776615524896 - modified: 1776615524896 - sortKey: -1776615518371 - description: "" - children: - - url: "{{_['api-host']}}/opex/v1/wallet/deposit/address" - name: assign - meta: - id: req_545b44b7943747659ad7508d5dd92724 - created: 1776615524897 - modified: 1776615524897 - isPrivate: false - description: "" - sortKey: -1776615518370 - method: GET - parameters: - - name: currency - value: BTC - disabled: false - - name: gatewayUuid - value: ong_abff8165-7e15-424f-b6f9-3e6e80941741 - disabled: false - authentication: - type: bearer - disabled: false - token: "{{_['user-token']}}" - prefix: "" - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - name: Kavenegar - meta: - id: fld_793d07a5e44d4567b1d8d41ae953c0c2 - created: 1776615524898 - modified: 1776615524898 - sortKey: -1776615518369 - description: "" - children: - - url: | - https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json - name: | - https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json - meta: - id: req_68cdb622a451476c80bf1cea5806d549 - created: 1776615524898 - modified: 1776615524898 - isPrivate: false - description: "" - sortKey: -1776615518368 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: receptor - value: "09336461763" - disabled: false - - name: sender - value: "90002350" - disabled: false - - name: message - value: |- - Code: 940852 - Dorost - دُرست - کد اعتبارسنجی: 940852 - - @beta.dorost.com #940852 - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true - - url: | - https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json - name: |- - https://api.kavenegar.com/v1/49634F384F6752574B654F3261756E744B5A4A6C57513D3D/sms/send.json - Copy - meta: - id: req_e76ade0a0638459e90d512fb5955fd81 - created: 1776615524899 - modified: 1776615524899 - isPrivate: false - description: "" - sortKey: -1776615518367 - method: POST - body: - mimeType: application/x-www-form-urlencoded - params: - - name: receptor - value: "09336461763" - disabled: false - - name: sender - value: "90002350" - disabled: false - - name: message - value: |- - Code: 940852 - Dorost - دُرست - کد اعتبارسنجی: 940852 - - @beta.dorost.com #940852 - disabled: false - headers: - - name: Content-Type - value: application/x-www-form-urlencoded - settings: - renderRequestBody: true - encodeUrl: true - followRedirects: global - cookies: - send: true - store: true - rebuildPath: true -cookieJar: - name: Default Jar - meta: - id: jar_f655ac09bdcefb9a402de78c571d5da38c23e416 - created: 1776614688094 - modified: 1776614688094 -environments: - name: Base Environment - meta: - id: env_f655ac09bdcefb9a402de78c571d5da38c23e416 - created: 1776614688092 - modified: 1776683924062 - isPrivate: false - subEnvironments: - - name: EXKY-PRD - meta: - id: env_21d5b741eb3845048f437b85ebe95cb7 - created: 1776682961306 - modified: 1776683571659 - isPrivate: false - sortKey: 1776682961306 - data: - host: https://api.exky.io - api-host: https://api.exky.io/api - auth-host: https://api.exky.io - wallet-host: https://api.exky.io/wallet - admin-host: https://api.exky.io/admin - config-host: https://api.exky.io/config - user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiWGwtUks3NnFhU1N5NTYxaU5wS19XX0NpN3VMQWRaMHhQUzJLaTJKc2NBIn0.eyJleHAiOjE3MjIwODcwMzQsImlhdCI6MTcyMjA4MzQzNCwianRpIjoiYTFhYzkzYjgtODMyYy00YWMyLWFjY2MtZWZhYmE1NjdkYWMyIiwiaXNzIjoiaHR0cHM6Ly9hcGkuZXhreS5pby9hdXRoL3JlYWxtcy9vcGV4Iiwic3ViIjoiZGJmN2Q5NmUtMjM4ZC00ODk0LThiOTEtMGI1ODBkY2IxMTk4IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNlc3Npb25fc3RhdGUiOiJkMzY0ZmU0ZS05M2ZhLTRjOTgtYmZmNi02YzhmMzVkNTNhYjciLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdfSwic2NvcGUiOiJ0cnVzdCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdLCJuYW1lIjoiQWRtaW4gRmluYW5jZSIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluLmZpbmFuY2VAZXhreS5pbyIsImdpdmVuX25hbWUiOiJBZG1pbiIsImZhbWlseV9uYW1lIjoiRmluYW5jZSIsImVtYWlsIjoiYWRtaW4uZmluYW5jZUBleGt5LmlvIn0.CNB1VEqYjcPSNaQM0CE35sTdeMlf2929aH8d2S9C1M-QYqJIIQFwb2T8Dnh2E8GosFr6Cstmr4JkIDOYVIJ6oqDxRNrB_kNa-ZolvAvuAWQSp38BCjC2zvc7un-CNirz5beQCmP3lboGBhbPqlGPfJjZDO-Eojq863eqGivc87iw7NAejUuMcMBmZ2W373V5xRsk0OxA9zu5ldhHSPrm93jheLjTb01Abwv31khAfqyoZ1kY1QiO3XTYGLtF3KQ3vuo0NgcuByCDZvWrhwzaYYMAWkqWVjY1w8bCw2seKNJoEkHVRYoJDQ0uZcVGWXzYG4GF-ITQGmLlKlN_JrAn4w - web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e - test-user-username: bot1 - test-user-password: 4TGx9sEV25jeCtSA - test-user-email: bot1@exky.io - admin-username: admin.finance@exky.io - admin-password: zm+>DcAF$,eK8:*(&_WaZ^ - super-admin-username: admin@exky.io - super-admin-password: 5M$Q?e7^eFq! - super-admin-token: "" - - name: Opex New - meta: - id: env_e0dac34ffaf7407c8170dfdff24d9dab - created: 1776682965594 - modified: 1776683716433 - isPrivate: false - sortKey: 1776682965594 - data: - host: https://api.exky.io - api-host: https://api.exky.io/api - admin-host: https://api.exky.io/admin - config-host: https://api.exky.io/config - user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiWGwtUks3NnFhU1N5NTYxaU5wS19XX0NpN3VMQWRaMHhQUzJLaTJKc2NBIn0.eyJleHAiOjE3MjIwODcwMzQsImlhdCI6MTcyMjA4MzQzNCwianRpIjoiYTFhYzkzYjgtODMyYy00YWMyLWFjY2MtZWZhYmE1NjdkYWMyIiwiaXNzIjoiaHR0cHM6Ly9hcGkuZXhreS5pby9hdXRoL3JlYWxtcy9vcGV4Iiwic3ViIjoiZGJmN2Q5NmUtMjM4ZC00ODk0LThiOTEtMGI1ODBkY2IxMTk4IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNlc3Npb25fc3RhdGUiOiJkMzY0ZmU0ZS05M2ZhLTRjOTgtYmZmNi02YzhmMzVkNTNhYjciLCJhY3IiOiIxIiwiYWxsb3dlZC1vcmlnaW5zIjpbIioiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdfSwic2NvcGUiOiJ0cnVzdCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInJvbGVzIjpbInVzZXJfYmFzaWMiLCJpbXBlcnNvbmF0aW9uIiwiYWRtaW5fZmluYW5jZSJdLCJuYW1lIjoiQWRtaW4gRmluYW5jZSIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluLmZpbmFuY2VAZXhreS5pbyIsImdpdmVuX25hbWUiOiJBZG1pbiIsImZhbWlseV9uYW1lIjoiRmluYW5jZSIsImVtYWlsIjoiYWRtaW4uZmluYW5jZUBleGt5LmlvIn0.CNB1VEqYjcPSNaQM0CE35sTdeMlf2929aH8d2S9C1M-QYqJIIQFwb2T8Dnh2E8GosFr6Cstmr4JkIDOYVIJ6oqDxRNrB_kNa-ZolvAvuAWQSp38BCjC2zvc7un-CNirz5beQCmP3lboGBhbPqlGPfJjZDO-Eojq863eqGivc87iw7NAejUuMcMBmZ2W373V5xRsk0OxA9zu5ldhHSPrm93jheLjTb01Abwv31khAfqyoZ1kY1QiO3XTYGLtF3KQ3vuo0NgcuByCDZvWrhwzaYYMAWkqWVjY1w8bCw2seKNJoEkHVRYoJDQ0uZcVGWXzYG4GF-ITQGmLlKlN_JrAn4w - web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e - test-user-username: bot1 - test-user-password: 4TGx9sEV25jeCtSA - test-user-email: bot1@exky.io - admin-username: admin.finance@exky.io - admin-password: zm+>DcAF$,eK8:*(&_WaZ^ - super-admin-username: admin@exky.io - super-admin-password: 5M$Q?e7^eFq! - super-admin-token: "" - - name: Opex Local - meta: - id: env_d89013a70ca04b6db11f00d8ae25c5ba - created: 1776683748193 - modified: 1778404577391 - isPrivate: false - sortKey: 1776683748193 - data: - host: http://localhost:8094 - api-host: http://localhost:8094 - auth-host: http://localhost:8083 - wallet-host: http://localhost:8091 - admin-host: http://localhost:8098 - config-host: http://localhost:9088 - user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJiRzQ1UmozQ2dqS0VmT2Y0X2pCekVmck1JdFVSX1Y1a180aGtfckVlcmVNIn0.eyJleHAiOjE3NTQzMTgwNDksImlhdCI6MTc1MzcxMzI0OSwianRpIjoiYjUzNTIyNjYtODhmZS00YzM4LTgzYmItZWQ1NDQ1MGEyYTIwIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsib3BleC1hcGkta2V5IiwiYWNjb3VudCJdLCJzdWIiOiJkNTFiZDc1Yy01YWI2LTQ4ZDEtOGMwNy04MjcyMjljZDM5N2UiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiZDI0YjBkMWYtMzFhZC00ODQ5LTkzMmEtOTRmNmM0NzBkMjczIiwic2NvcGUiOiJ0cnVzdCIsInBlcm1pc3Npb25zIjpbImRlcG9zaXQ6d3JpdGUiLCJvcmRlcjp3cml0ZSIsImFkZHJlc3M6YXNzaWduIl0sInJvbGVzIjpbInVzZXItMSIsImRlZmF1bHQtcm9sZXMtb3BleCIsInVzZXIiXSwiZW1haWwiOiJoaUBvcGV4LmRldiIsInVzZXJuYW1lIjoiaGlAb3BleC5kZXYifQ.l5X2MyJ7UgAqwdY0txW-kjmdThaTNwDGLqqbfp9I46JY_G_1TrPl5PcJNRPM4TsB4IexI8vgJc6zk6Mqo7H3EGx1cpCTvaYLG576SlP3MUd_9p9T3ogzZ0BIQ8cO7IpUqqnzfCiTZODAnXg6fF3vN57TfbDrjR7rzjUigIYRJBUKTVyUeY-S9buAXyyJapqmOJ-7mSJ0nxdOSxAR_KGEXiDCb7jJ1S4UnwNi0UKZvm781wCGN4s_kr-dZCTGYE9x1TOUHYCfwF3It1DCupmUUUm1R_Bljpizndz3wPJzCucWsc-F3QedXJdx-LVbRBTDF_3d - client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjaWwwNVZPYzlORjl6Rm9LMlVOYllEcHdlaWk2bFJQTmZ2NmZKdXJhVWZjIn0.eyJleHAiOjE3NzgzNDg0NzAsImlhdCI6MTc3ODM0NDg3MCwianRpIjoiYTQ3NjcwZTktODc2Ny00OWViLWEzMGEtNGI3NzllZmZmZTMxIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsid2ViLWFwcCIsImFjY291bnQiXSwic3ViIjoiOGI4N2IzMDUtMGNmOC00NWJiLTlmZmItMDZiMDc2YWJmYzlmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNpZCI6IjVjNDJjMmVmLThiNGEtNGViOC1iZTM1LWMzODM3NTI3MmY1NiIsInNjb3BlIjoidHJ1c3QiLCJwZXJtaXNzaW9ucyI6WyJkZXBvc2l0OndyaXRlIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iLCJkZXBvc2l0OndyaXRlIiwid2l0aGRyYXc6d3JpdGUiLCJ2b3VjaGVyOnN1Ym1pdCIsImJhbmtfYWNjb3VudDp3cml0ZSIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iXSwicm9sZXMiOlsidXNlci0xIiwiZGVmYXVsdC1yb2xlcy1vcGV4IiwiYWRtaW4iLCJ1c2VyLTIiLCJ1c2VyIl0sImVtYWlsIjoiYWRtaW5Ab3BleC5kZXYiLCJ1c2VybmFtZSI6ImFkbWluIn0.mNMxjk4TDjz0UuQm5-Sw43ed1Ug-7qJfq_2T2fsGagaWoKDoIByC9sbwb7x6lOszd7HQMqNZYZfDkTQWqMLoEBnoa4UtvNarGz69gZi9n0MDTyxXPmRsL_FB_fSqnN-VompXwW8fPa0S90H2bgP1O7_rkZdIMGMBCLRyyNbct2ln4IdlzSepQ532MWB4UrNT8Rs9rheixpa-1PW1mqhoOhwPXz5zLlA7xNoKho_eo9SfJzmlpiOnwugHmQBXG5O9TlycDCBtDLeLO-RuCTM25oyJR0DWqJT7VEfQ979nXyBqDoNiROMcs8UqoE5cx3HXg92xZ4KnrK3UPiKrLQYzdw - super-admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJjaWwwNVZPYzlORjl6Rm9LMlVOYllEcHdlaWk2bFJQTmZ2NmZKdXJhVWZjIn0.eyJleHAiOjE3NzgzNDg0NzAsImlhdCI6MTc3ODM0NDg3MCwianRpIjoiYTQ3NjcwZTktODc2Ny00OWViLWEzMGEtNGI3NzllZmZmZTMxIiwiaXNzIjoiaHR0cDovL2tleWNsb2FrOjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOlsid2ViLWFwcCIsImFjY291bnQiXSwic3ViIjoiOGI4N2IzMDUtMGNmOC00NWJiLTlmZmItMDZiMDc2YWJmYzlmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoid2ViLWFwcCIsInNpZCI6IjVjNDJjMmVmLThiNGEtNGViOC1iZTM1LWMzODM3NTI3MmY1NiIsInNjb3BlIjoidHJ1c3QiLCJwZXJtaXNzaW9ucyI6WyJkZXBvc2l0OndyaXRlIiwib3JkZXI6d3JpdGUiLCJhZGRyZXNzOmFzc2lnbiIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iLCJkZXBvc2l0OndyaXRlIiwid2l0aGRyYXc6d3JpdGUiLCJ2b3VjaGVyOnN1Ym1pdCIsImJhbmtfYWNjb3VudDp3cml0ZSIsIm9yZGVyOndyaXRlIiwiYWRkcmVzczphc3NpZ24iXSwicm9sZXMiOlsidXNlci0xIiwiZGVmYXVsdC1yb2xlcy1vcGV4IiwiYWRtaW4iLCJ1c2VyLTIiLCJ1c2VyIl0sImVtYWlsIjoiYWRtaW5Ab3BleC5kZXYiLCJ1c2VybmFtZSI6ImFkbWluIn0.mNMxjk4TDjz0UuQm5-Sw43ed1Ug-7qJfq_2T2fsGagaWoKDoIByC9sbwb7x6lOszd7HQMqNZYZfDkTQWqMLoEBnoa4UtvNarGz69gZi9n0MDTyxXPmRsL_FB_fSqnN-VompXwW8fPa0S90H2bgP1O7_rkZdIMGMBCLRyyNbct2ln4IdlzSepQ532MWB4UrNT8Rs9rheixpa-1PW1mqhoOhwPXz5zLlA7xNoKho_eo9SfJzmlpiOnwugHmQBXG5O9TlycDCBtDLeLO-RuCTM25oyJR0DWqJT7VEfQ979nXyBqDoNiROMcs8UqoE5cx3HXg92xZ4KnrK3UPiKrLQYzdw - test-user-username: test@opex.dev - test-user-password: "12345678" - test-user-email: test@opex.dev - admin-username: admin@gmail.com - admin-password: "12345678" - user-token-2: "" - v2auth-host: http://localhost:8184 - api-key: sdsd - secret: sdfsdf - profile-host: "" - device-host: "" - super-admin-username: "" - super-admin-password: "" - acc-host: "" - bc-gateway-host: http://localhost:8095 - "": "" - - name: Opex Dev - meta: - id: env_e079e933f735438b87e203e51394b838 - created: 1776683906503 - modified: 1776683957963 - isPrivate: false - sortKey: 1776683906503 - data: - host: https://api.opex.dev - api-host: https://api.opex.dev/api - auth-host: https://api.opex.dev - wallet-host: https://api.opex.dev/wallet - admin-host: https://api.opex.dev/admin - config-host: https://api.opex.dev/config - user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NTcxNzI1OTMsImlhdCI6MTc1NzE2ODk5MywianRpIjoiYTNjYjJjYWEtMmI1My00YTg1LWI1NDYtM2IyMzBkMDVhNjcxIiwiaXNzIjoiaHR0cDovL2tjLm9wZXguZGV2OjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJvcGV4LWFwaS1rZXkiLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiODdkZjFmMGYtNjhmNy00ZjA4LTgzMjktZjI5MzAxNDEzZTZkIiwic2NvcGUiOiJ0cnVzdCIsImZpcnN0TmFtZSI6Imtvb3Jvc2giLCJsYXN0TmFtZSI6ImF6aW1pIiwicGVybWlzc2lvbnMiOlsiYWxsIiwiZGVwb3NpdDp3cml0ZSJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJzdXBlci1hZG1pbiIsImRlZmF1bHQtcm9sZXMtb3BleCIsImFkbWluIiwidXNlciJdLCJlbWFpbCI6ImF6aW1pQG9wZXguY29tIiwidXNlcm5hbWUiOiJhemltaSJ9.Cy1gtf1YgRlsvA3YK4oVUdQAzOhkom298M5BMGtcKYkddGzzfq69TiIbh3T0jr915NOCEFW0NR38GiWHcA7W1FtRbKDGFNiGSucLBaL0vkmtz0u5L2GWuSQhYVGulFnqka0yCw8tRjWGhsSU3AVghEMwnCwgeeD3Usx9DHp-m-gQ4VJvmHnv-voezY5e55HspJFHL8lYenqgXlyFugJEHCnYwKs92MmGLFBNsPhRB3hXdA8ijVWif1sD0Vv8RGTrU6gYBUphzMwbvce3vP4VpWRqmc8-ZXPCDM6r4pq8hxBvih28S2KKTC3p3WN5CslrDXrq2dWLghrRnCXOXGKUDg - client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJoZWRfenhDZjh0QzNzZmxjVzdzZm5JWERkb0tSdnhva21DdnZ3NTZXdGRvIn0.eyJleHAiOjE3MDU0ODAzODEsImlhdCI6MTcwNTM5Mzk4MSwianRpIjoiODVjZmIzMzQtYzFjMi00MGEyLWIzYTItNDQ0MmZkMWNlZmUwIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjdhZGRlZGY0LTRjZjEtNDJjMC04YWI5LTRhMDgwOGQwMTE3OCIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZWNlMWJhNzctMDA0NC00MmFhLTk5OTctNGZlNzg4MWFhYTA0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXSwibmFtZSI6ImZpbmFuY2UgYWRtaW4iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJmaW5hbmNlQG9wZXguZGV2IiwiZ2l2ZW5fbmFtZSI6ImZpbmFuY2UiLCJmYW1pbHlfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJmaW5hbmNlQG9wZXguZGV2In0.o6M37eQZ3O2a6Vf8W8zoRhcqHoanJF2HgcwWprqjJox-eOv6g5xMKA0YtQrwxAm3R_ypdevfy80rmjODKLfYtsM0PI223gdi1lsA24WqdX2yfYoEZpCnTkHLKDqYOn4kJ1Ox0fx-AtLXiwYK40HRCTBXuumu4XDw3JM2edVLr8-eaypY5wudWhN-pymdrUZZn0kDNpdwgSwMGYbVoAsKEBhqdJL5XvR5n3gIKOs3Gv9yQi8MsBln_mq6OUYiObT1cFZh2s0fQcBDXlzzy789ulEKnK1jFpXW5PwkEZPMzsF2AtQxBuRvhscWMsH28fUErezmF-cX53hh8-2d7QITmw - web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e - test-user-username: test1@opex.dev - test-user-password: "12345678" - test-user-email: test1@opex.dev - admin-username: finance@opex.dev - admin-password: "12345678" - user-uuid: 7440dffe-8332-4775-83c2-b5880c526c48 - market-host: https://api.opex.dev/market - super-admin-username: azimi@opex.dev - super-admin-password: Aaswq123 - super-admin-token: "" - bc-gateway-host: https://api.opex.dev/bc-gateway - v2auth-host: https://v2auth.opex.dev - profile-host: https://api.opex.dev/profile - - name: Exky-UAT - meta: - id: env_469269b98298468691dd8f1f8aee80cd - created: 1776684069696 - modified: 1776684101341 - isPrivate: false - sortKey: 1776684069696 - data: - host: https://api-uat.exky.io - api-host: https://api-uat.exky.io/api - auth-host: https://api-uat.exky.io - wallet-host: https://api-uat.exky.io/wallet - admin-host: https://api-uat.exky.io/admin - config-host: https://api-uat.exky.io/config - user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1V20xTXJzMHRjTldmM2NSTHpHNEJseHEzS3JqNUloNGczX2RuWS1uNmpzIn0.eyJleHAiOjE2NDU0NzI0OTIsImlhdCI6MTY0NTQzNjQ5MiwianRpIjoiOTFkYWUxOWMtMTVmZi00ZDJmLWE0ZjItNTMyODFjN2VlMzIyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJlNDUwNWNiOC02ZDcyLTRlY2MtYjhlMC0zNjZhZjM1MmU0YjIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2Vzc2lvbl9zdGF0ZSI6ImIyNmRmNDRkLTY4Y2UtNGQ5NC05YmNkLTlkN2NkYTljMTRkNyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiaW1wZXJzb25hdGlvbiIsImZpbmFuY2UtYWRtaW4iXX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6WyJpbXBlcnNvbmF0aW9uIiwiZmluYW5jZS1hZG1pbiJdLCJuYW1lIjoiZiBmZiIsInByZWZlcnJlZF91c2VybmFtZSI6ImZpbmFuY2UiLCJnaXZlbl9uYW1lIjoiZiIsImZhbWlseV9uYW1lIjoiZmYiLCJlbWFpbCI6ImZpbmFuY2VAZy5jb20ifQ.nS537ox40f2bf4pEVIKgVT8U9FQB9ME4FrtLBH7FOA7R-OzEQmcCgdMayTuRgrpohfygXjaVs_T4xytClNGOR6CTyiGi3Ay7NXzVE-P5JHW9y9catX3VKaS-acNOdtzKvkIvTPS8_0C1jdkRYDLxvPl47lbexbFYQ7a-7J1YNAIQzwRBEPhM-GX1a9mgImH2_mzNtgogLjIvqSNFwWJgnvYaz_Bk_mULsQANVUXk2GSMEDPXAMCTG-TyQXGmxE--rYdEFsy6VIu90sANs3mswtsYo7yeL1T1-jxV8A927FTjBtsGf0KGvV2AjMelMkfm06R1xP0HEVWr_GgmzoLMSg - web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e - test-user-username: demo1 - test-user-password: "12345678" - test-user-email: test@opex.dev - - name: Beta dorost - meta: - id: env_8c4ff57b4a294f50b9579c397e9d31c5 - created: 1776684119860 - modified: 1776684147895 - isPrivate: false - sortKey: 1776684119860 - data: - host: https://api.opex.dev - api-host: https://api.opex.dev/api - auth-host: https://api.opex.dev - wallet-host: https://api.opex.dev/wallet - admin-host: https://api.opex.dev/admin - config-host: https://api.opex.dev/config - user-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQMGYtWTU1MWtEbkpBS1RxLWZEVHpnYTlIM084bGpaRzVJTmVvMUcxU3hrIn0.eyJleHAiOjE3NTcxNzI1OTMsImlhdCI6MTc1NzE2ODk5MywianRpIjoiYTNjYjJjYWEtMmI1My00YTg1LWI1NDYtM2IyMzBkMDVhNjcxIiwiaXNzIjoiaHR0cDovL2tjLm9wZXguZGV2OjgwODAvcmVhbG1zL29wZXgiLCJhdWQiOiJvcGV4LWFwaS1rZXkiLCJzdWIiOiJlNGE4ODY1ZS04NGJjLTQ2ZTItOGU3YS03MDYxMGZmMDk3NTMiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwic2lkIjoiODdkZjFmMGYtNjhmNy00ZjA4LTgzMjktZjI5MzAxNDEzZTZkIiwic2NvcGUiOiJ0cnVzdCIsImZpcnN0TmFtZSI6Imtvb3Jvc2giLCJsYXN0TmFtZSI6ImF6aW1pIiwicGVybWlzc2lvbnMiOlsiYWxsIiwiZGVwb3NpdDp3cml0ZSJdLCJyb2xlcyI6WyJ1c2VyLTEiLCJzdXBlci1hZG1pbiIsImRlZmF1bHQtcm9sZXMtb3BleCIsImFkbWluIiwidXNlciJdLCJlbWFpbCI6ImF6aW1pQG9wZXguY29tIiwidXNlcm5hbWUiOiJhemltaSJ9.Cy1gtf1YgRlsvA3YK4oVUdQAzOhkom298M5BMGtcKYkddGzzfq69TiIbh3T0jr915NOCEFW0NR38GiWHcA7W1FtRbKDGFNiGSucLBaL0vkmtz0u5L2GWuSQhYVGulFnqka0yCw8tRjWGhsSU3AVghEMwnCwgeeD3Usx9DHp-m-gQ4VJvmHnv-voezY5e55HspJFHL8lYenqgXlyFugJEHCnYwKs92MmGLFBNsPhRB3hXdA8ijVWif1sD0Vv8RGTrU6gYBUphzMwbvce3vP4VpWRqmc8-ZXPCDM6r4pq8hxBvih28S2KKTC3p3WN5CslrDXrq2dWLghrRnCXOXGKUDg - client-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJreENqRGVHeDBQRjJUMF90czNCbUV6NjJlYTl0aURUdmFIb2NaNnJvN1MwIn0.eyJleHAiOjE2NTQwNjgyNzEsImlhdCI6MTY1Mzk4MTg3MSwianRpIjoiMDNhMTI4NTItOTVmMS00YjI0LWEwOWYtZjY2YjBhZDRlOGQyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgzL2F1dGgvcmVhbG1zL29wZXgiLCJzdWIiOiJhZWNhODFkOS1jODY2LTQ0M2MtOTkwMC1iZWMxMzE2OGFiODYiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJ3ZWItYXBwIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJjbGllbnRJZCI6IndlYi1hcHAiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtd2ViLWFwcCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTguMC4xIn0.G8rfAN19goXSdxcEbcnWMbK50kcl-ri8jquzPXYlN2OhvOfp-jBHEJANWX9v42VzVhgklGly2q71e5dSD71ndJPSly2wpoRmHg2rdqRokjNUq-nJgCnYBn5J0yeGrcx7_4T6LTw1O0ClH11D4louMM2kz1dHzFen7q1Df_zDRLf3N9zOHuayw38KxiX49whXVrtfj6NR56BT14wleP2RRIgfPpqqlSrPRfgsF3sfINooJW7G8xEZe4pEv35w7ps1gsZXU7sFeCCaRft85pWhbVt3lJgBQjn9S8e5X6Qd1kmhcDZQxNTAzuOynozBjH2uT-sk3UTBvQ0DDifDfnN5QA - admin-token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJoZWRfenhDZjh0QzNzZmxjVzdzZm5JWERkb0tSdnhva21DdnZ3NTZXdGRvIn0.eyJleHAiOjE3MDU0ODAzODEsImlhdCI6MTcwNTM5Mzk4MSwianRpIjoiODVjZmIzMzQtYzFjMi00MGEyLWIzYTItNDQ0MmZkMWNlZmUwIiwiaXNzIjoiaHR0cHM6Ly9hcGkub3BleC5kZXYvYXV0aC9yZWFsbXMvb3BleCIsInN1YiI6IjdhZGRlZGY0LTRjZjEtNDJjMC04YWI5LTRhMDgwOGQwMTE3OCIsInR5cCI6IkJlYXJlciIsImF6cCI6IndlYi1hcHAiLCJzZXNzaW9uX3N0YXRlIjoiZWNlMWJhNzctMDA0NC00MmFhLTk5OTctNGZlNzg4MWFhYTA0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIqIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXX0sInNjb3BlIjoidHJ1c3QgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJyb2xlcyI6WyJ1c2VyX2Jhc2ljIiwiaW1wZXJzb25hdGlvbiIsImFkbWluX2ZpbmFuY2UiXSwibmFtZSI6ImZpbmFuY2UgYWRtaW4iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJmaW5hbmNlQG9wZXguZGV2IiwiZ2l2ZW5fbmFtZSI6ImZpbmFuY2UiLCJmYW1pbHlfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJmaW5hbmNlQG9wZXguZGV2In0.o6M37eQZ3O2a6Vf8W8zoRhcqHoanJF2HgcwWprqjJox-eOv6g5xMKA0YtQrwxAm3R_ypdevfy80rmjODKLfYtsM0PI223gdi1lsA24WqdX2yfYoEZpCnTkHLKDqYOn4kJ1Ox0fx-AtLXiwYK40HRCTBXuumu4XDw3JM2edVLr8-eaypY5wudWhN-pymdrUZZn0kDNpdwgSwMGYbVoAsKEBhqdJL5XvR5n3gIKOs3Gv9yQi8MsBln_mq6OUYiObT1cFZh2s0fQcBDXlzzy789ulEKnK1jFpXW5PwkEZPMzsF2AtQxBuRvhscWMsH28fUErezmF-cX53hh8-2d7QITmw - web-app-secret: d3d927e4-6ad6-4545-9f6f-0725a79b2d9e - test-user-username: test1@opex.dev - test-user-password: "12345678" - test-user-email: test1@opex.dev - admin-username: finance@opex.dev - admin-password: "12345678" - user-uuid: 7440dffe-8332-4775-83c2-b5880c526c48 - market-host: https://api.opex.dev/market - super-admin-username: azimi@opex.dev - super-admin-password: Aaswq123 - super-admin-token: "" - bc-gateway-host: https://api.opex.dev/bc-gateway - v2auth-host: https://v2auth.opex.dev - profile-host: https://api.opex.dev/profile From fe66fd7e3b401b1a00a97abd5ec57f67ec9eb88e Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sun, 10 May 2026 20:20:27 +0330 Subject: [PATCH 03/56] RM unused files --- api.csv | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 api.csv diff --git a/api.csv b/api.csv deleted file mode 100644 index f40a56206..000000000 --- a/api.csv +++ /dev/null @@ -1,31 +0,0 @@ -Public API Path,Internal Module Path,Method,Module,Through API Layer,Auth Required,Roles/Permissions,Controller,Notes -/opex/v1/address-book,UNKNOWN,POST,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.addAddressBook(token, request) -/opex/v1/address-book,UNKNOWN,GET,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.getAllAddressBooks(token) -/opex/v1/address-book/{id},UNKNOWN,DELETE,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.deleteAddressBook(token, id) -/opex/v1/address-book/{id},UNKNOWN,PUT,profile-app,YES,YES,NOT CLEAR,AddressBookController,Proxy: ProfileProxy.updateAddressBook(token, id, request) -/opex/v1/admin/storage,UNKNOWN,GET,storage,YES,YES,ADMIN? (NEEDS REVIEW),StorageAdminController,Download file by bucket/key -/opex/v1/admin/storage,UNKNOWN,POST,storage,YES,YES,ADMIN? (NEEDS REVIEW),StorageAdminController,Upload multipart file; returns URL -/opex/v1/admin/storage,UNKNOWN,DELETE,storage,YES,YES,ADMIN? (NEEDS REVIEW),StorageAdminController,Delete file by bucket/key -/opex/v1/withdraw,UNKNOWN,POST,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Request withdraw -/opex/v1/withdraw/{withdrawUuid}/cancel,UNKNOWN,PUT,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Cancel withdraw -/opex/v1/withdraw/{withdrawUuid},UNKNOWN,GET,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Find withdraw -/opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request,UNKNOWN,POST,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Request withdraw OTP -/opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify,UNKNOWN,POST,wallet-app,YES,YES,NOT CLEAR,WithdrawController,Verify withdraw OTP (otpCode as query) -/opex/v1/deposit,UNKNOWN,POST,wallet-app,YES,NOT CLEAR,NOT CLEAR,DepositController,Security not explicit at controller; verify upstream security -/opex/v1/admin/wallet/users,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),WalletAdminController,List users wallets -/opex/v1/admin/wallet/system/total,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),WalletAdminController,System wallets total -/opex/v1/admin/wallet/users/total,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),WalletAdminController,Users wallets total -/opex/v1/voucher/{code},UNKNOWN,PUT,wallet-app,YES,YES,USER (implicit),VoucherController,Submit voucher using token -/opex/v1/user/data/trade/volume,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Requires symbol and interval -/opex/v1/user/data/trade/volume/total,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Requires interval -/opex/v1/user/data/fee,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Returns UserFee -/opex/v1/user/data/withdraw/volume/total,UNKNOWN,GET,accountant-app,YES,YES,USER (implicit),UserDataController,Optional interval string mapped to enum -/opex/v1/admin/currency/{currency}/localization,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Get currency localization -/opex/v1/admin/currency/{currency}/localization,UNKNOWN,POST,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Save currency localizations -/opex/v1/admin/currency/localization/{id},UNKNOWN,DELETE,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Delete currency localization by id -/opex/v1/admin/terminal/{terminalUuid}/localization,UNKNOWN,GET,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Get terminal localization -/opex/v1/admin/terminal/{terminalUuid}/localization,UNKNOWN,POST,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Save terminal localizations -/opex/v1/admin/terminal/localization/{id},UNKNOWN,DELETE,wallet-app,YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,Delete terminal localization by id -/opex/v1/admin/gateway/{gatewayUuid}/localization,UNKNOWN,GET,MIXED(wallet-app;bc-gateway-app),YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,If uuid starts with ofg → wallet; ong → bc-gateway -/opex/v1/admin/gateway/{gatewayUuid}/localization,UNKNOWN,POST,MIXED(wallet-app;bc-gateway-app),YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,If uuid starts with ofg → wallet; ong → bc-gateway -/opex/v1/admin/gateway/{gatewayUuid}/localization/{id},UNKNOWN,DELETE,MIXED(wallet-app;bc-gateway-app),YES,YES,ADMIN? (NEEDS REVIEW),LocalizationAdminController,If uuid starts with ofg → wallet; ong → bc-gateway From 94664a7c9958ad14d09f0ae47d68c1770c7000e9 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sun, 10 May 2026 22:03:26 +0330 Subject: [PATCH 04/56] Update the swagger security config --- Insomnia_2026-05-10.json | 817 ++++++++++++++++-- .../opex/api/app/config/OpenApiConfig.kt | 37 + .../opex/api/app/config/SwaggerConfig.kt | 96 -- .../src/main/resources/application.yml | 9 +- .../ports/binance/config/SecurityConfig.kt | 20 +- .../opex/controller/BankAccountController.kt | 180 +++- docker-compose.yml | 4 + 7 files changed, 997 insertions(+), 166 deletions(-) create mode 100644 api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt delete mode 100644 api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/SwaggerConfig.kt diff --git a/Insomnia_2026-05-10.json b/Insomnia_2026-05-10.json index 98e818626..4a307ea93 100644 --- a/Insomnia_2026-05-10.json +++ b/Insomnia_2026-05-10.json @@ -40,58 +40,769 @@ "key": "logo.png" } }, - - { "_id": "fld_api_opex_rest", "_type": "request_group", "parentId": "wrk_opex", "name": "api-ports / api-opex-rest" }, - - { "_id": "fld_addressbook", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Address Book" }, - { "_id": "req_addr_add", "_type": "request", "parentId": "fld_addressbook", "name": "POST /opex/v1/address-book", "method": "POST", "description": "Body = AddAddressBookItemRequest { name:String, address:String, addressType:String }.\nNotes: addressType: CRYPTO | BANK (NEEDS REVIEW if more types exist).", "url": "{{ _['api-host'] }}/opex/v1/address-book", "body": { "mimeType": "application/json", "text": "{\n \"name\": \"Home Wallet\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_addr_list", "_type": "request", "parentId": "fld_addressbook", "name": "GET /opex/v1/address-book", "method": "GET", "description": "Returns List for authenticated user.", "url": "{{ _['api-host'] }}/opex/v1/address-book", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_addr_delete", "_type": "request", "parentId": "fld_addressbook", "name": "DELETE /opex/v1/address-book/{id}", "method": "DELETE", "description": "Path param: id (int64). Deletes address book entry.", "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_addr_update", "_type": "request", "parentId": "fld_addressbook", "name": "PUT /opex/v1/address-book/{id}", "method": "PUT", "description": "Path param: id (int64). Body = AddAddressBookItemRequest.", "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", "body": { "mimeType": "application/json", "text": "{\n \"name\": \"Updated Name\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - - { "_id": "fld_storage_admin", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Storage Admin" }, - { "_id": "req_storage_get", "_type": "request", "parentId": "fld_storage_admin", "name": "GET /opex/v1/admin/storage", "method": "GET", "description": "Query params: bucket:string, key:string. Returns file bytes.", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { "name": "bucket", "value": "{{ _['bucket'] }}", "description": "Bucket name" }, { "name": "key", "value": "{{ _['key'] }}", "description": "Object key" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_storage_post", "_type": "request", "parentId": "fld_storage_admin", "name": "POST /opex/v1/admin/storage", "method": "POST", "description": "Multipart upload. Params: bucket, key, isPublic (bool). Part: file.", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { "name": "bucket", "value": "{{ _['bucket'] }}", "description": "Bucket name" }, { "name": "key", "value": "{{ _['key'] }}", "description": "Object key" }, { "name": "isPublic", "value": "false", "description": "Publicly accessible if true" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" }, "body": { "mimeType": "multipart/form-data", "params": [ { "name": "file", "type": "file", "fileName": "/path/to/file.png" } ], "paramsOrder": [ "file" ] } }, - { "_id": "req_storage_delete", "_type": "request", "parentId": "fld_storage_admin", "name": "DELETE /opex/v1/admin/storage", "method": "DELETE", "description": "Query params: bucket, key. Deletes file.", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { "name": "bucket", "value": "{{ _['bucket'] }}", "description": "Bucket name" }, { "name": "key", "value": "{{ _['key'] }}", "description": "Object key" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - - { "_id": "fld_withdraw", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Withdraw" }, - { "_id": "req_withdraw_post", "_type": "request", "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw", "method": "POST", "description": "Body = RequestWithdrawBody { currency:String, amount:BigDecimal, destSymbol:String?, destAddress:String, destNetwork:String?, destNote:String?, gatewayUuid:String? }.", "url": "{{ _['api-host'] }}/opex/v1/withdraw", "body": { "mimeType": "application/json", "text": "{\n \"currency\": \"USDT\",\n \"amount\": 50.00,\n \"destSymbol\": null,\n \"destAddress\": \"0x...\",\n \"destNetwork\": null,\n \"destNote\": null,\n \"gatewayUuid\": null\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_withdraw_cancel", "_type": "request", "parentId": "fld_withdraw", "name": "PUT /opex/v1/withdraw/{withdrawUuid}/cancel", "method": "PUT", "description": "Path param: withdrawUuid (string). Cancels withdraw.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/cancel", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_withdraw_find", "_type": "request", "parentId": "fld_withdraw", "name": "GET /opex/v1/withdraw/{withdrawUuid}", "method": "GET", "description": "Path param: withdrawUuid (string). Returns WithdrawResponse.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_withdraw_otp_req", "_type": "request", "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request", "method": "POST", "description": "Path params: withdrawUuid (string), otpType: OTPType = SMS | EMAIL. Triggers OTP send.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/request", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_withdraw_otp_verify", "_type": "request", "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify", "method": "POST", "description": "Path params: withdrawUuid, otpType: OTPType = SMS | EMAIL. Query param: otpCode (string). Verifies OTP.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/verify", "parameters": [ { "name": "otpCode", "value": "{{ _['otpCode'] }}", "description": "OTP code" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - - { "_id": "fld_deposit", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Deposit" }, - { "_id": "req_deposit_post", "_type": "request", "parentId": "fld_deposit", "name": "POST /opex/v1/deposit", "method": "POST", "description": "Body = RequestDepositBody { symbol:String, receiverUuid:String, receiverWalletType:WalletType, amount:BigDecimal, description:String?, transferRef:String?, gatewayUuid:String?, chain:String? }. WalletType values depend on implementation (e.g., MAIN).", "url": "{{ _['api-host'] }}/opex/v1/deposit", "body": { "mimeType": "application/json", "text": "{\n \"symbol\": \"USDT\",\n \"receiverUuid\": \"{{ _['id'] }}\",\n \"receiverWalletType\": \"MAIN\",\n \"amount\": 100.00,\n \"description\": null,\n \"transferRef\": null,\n \"gatewayUuid\": null,\n \"chain\": null\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ] }, - - { "_id": "fld_wallet_admin", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Wallet Admin" }, - { "_id": "req_wallet_admin_users", "_type": "request", "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/users", "method": "GET", "description": "Query: uuid?, currency?, excludeSystem=false, limit?, offset?. Returns List.", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users", "parameters": [ { "name": "excludeSystem", "value": "false", "description": "Exclude system wallets" }, { "name": "limit", "value": "10", "description": "Page size" }, { "name": "offset", "value": "0", "description": "Page offset" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_wallet_admin_system_total", "_type": "request", "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/system/total", "method": "GET", "description": "Returns List.", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/system/total", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_wallet_admin_users_total", "_type": "request", "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/users/total", "method": "GET", "description": "Returns List.", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users/total", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - - { "_id": "fld_voucher", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Voucher" }, - { "_id": "req_voucher_put", "_type": "request", "parentId": "fld_voucher", "name": "PUT /opex/v1/voucher/{code}", "method": "PUT", "description": "Path param: code (string). Returns SubmitVoucherResponse.", "url": "{{ _['api-host'] }}/opex/v1/voucher/{{ _['code'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - - { "_id": "fld_user_data", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "User Data" }, - { "_id": "req_user_data_trade_volume", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/trade/volume", "method": "GET", "description": "Query: symbol (string), interval (Interval = Day | Week | Month | Year). Returns BigDecimal.", "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume", "parameters": [ { "name": "symbol", "value": "{{ _['symbol'] }}", "description": "Symbol, e.g., BTCUSDT" }, { "name": "interval", "value": "{{ _['interval'] }}", "description": "Interval: Day | Week | Month | Year" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_user_data_trade_volume_total", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/trade/volume/total", "method": "GET", "description": "Query: interval (Interval = Day | Week | Month | Year). Returns BigDecimal.", "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume/total", "parameters": [ { "name": "interval", "value": "{{ _['interval'] }}", "description": "Interval: Day | Week | Month | Year" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_user_data_fee", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/fee", "method": "GET", "description": "Returns UserFee.", "url": "{{ _['api-host'] }}/opex/v1/user/data/fee", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_user_data_withdraw_total", "_type": "request", "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/withdraw/volume/total", "method": "GET", "description": "Query: interval? (label mapped to Interval). Returns BigDecimal.", "url": "{{ _['api-host'] }}/opex/v1/user/data/withdraw/volume/total", "parameters": [ { "name": "interval", "value": "{{ _['interval'] }}", "description": "Optional label: Day | Week | Month | Year" } ], "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - - { "_id": "fld_bank_account", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Bank Account" }, - { "_id": "req_bank_add", "_type": "request", "parentId": "fld_bank_account", "name": "POST /opex/v1/bank-account", "method": "POST", "description": "Body = AddBankAccountRequest { name?:String, cardNumber?:String, iban?:String }.", "url": "{{ _['api-host'] }}/opex/v1/bank-account", "body": { "mimeType": "application/json", "text": "{\n \"name\": \"My Bank\",\n \"cardNumber\": null,\n \"iban\": \"IRxxxxxxxxxxxx\"\n}" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_bank_list", "_type": "request", "parentId": "fld_bank_account", "name": "GET /opex/v1/bank-account", "method": "GET", "description": "Returns List.", "url": "{{ _['api-host'] }}/opex/v1/bank-account", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - { "_id": "req_bank_delete", "_type": "request", "parentId": "fld_bank_account", "name": "DELETE /opex/v1/bank-account/{id}", "method": "DELETE", "description": "Path param: id (int64). Deletes bank account.", "url": "{{ _['api-host'] }}/opex/v1/bank-account/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['user-token']}}", "prefix": "" } }, - - { "_id": "fld_localization_admin", "_type": "request_group", "parentId": "fld_api_opex_rest", "name": "Localization Admin" }, - { "_id": "req_loc_currency_get", "_type": "request", "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/currency/{currency}/localization", "method": "GET", "description": "Path: currency (string). Returns CurrencyLocalizationResponse.", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_currency_post", "_type": "request", "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/currency/{currency}/localization", "method": "POST", "description": "Path: currency. Body = List { id?:Long, name?:String, title?:String, alias?:String, description?:String, shortDescription?:String, language:String }.", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", "body": { "mimeType": "application/json", "text": "[\n {\n \"id\": null,\n \"name\": \"USDT\",\n \"title\": \"Tether USD\",\n \"alias\": \"Tether\",\n \"description\": \"Stablecoin description\",\n \"shortDescription\": \"Stablecoin\",\n \"language\": \"en\"\n }\n]" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_currency_delete", "_type": "request", "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/currency/localization/{id}", "method": "DELETE", "description": "Path: id (int64). Deletes one currency localization.", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/localization/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_terminal_get", "_type": "request", "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/terminal/{terminalUuid}/localization", "method": "GET", "description": "Path: terminalUuid. Returns TerminalLocalizationResponse.", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_terminal_post", "_type": "request", "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/terminal/{terminalUuid}/localization", "method": "POST", "description": "Path: terminalUuid. Body = List { id?:Long, description?:String, owner?:String, language:String }.", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", "body": { "mimeType": "application/json", "text": "[\n {\n \"id\": null,\n \"description\": \"Terminal description\",\n \"owner\": \"OPEX\",\n \"language\": \"en\"\n }\n]" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_terminal_delete", "_type": "request", "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/terminal/localization/{id}", "method": "DELETE", "description": "Path: id (int64). Deletes one terminal localization.", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/localization/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_gateway_get", "_type": "request", "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/gateway/{gatewayUuid}/localization", "method": "GET", "description": "Path: gatewayUuid. Returns GatewayLocalizationResponse. Route based on prefix of UUID (ofg | ong).", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_gateway_post", "_type": "request", "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/gateway/{gatewayUuid}/localization", "method": "POST", "description": "Path: gatewayUuid. Body = List { id?:Long, depositDescription?:String, withdrawDescription?:String, language:String }.", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", "body": { "mimeType": "application/json", "text": "[\n {\n \"id\": null,\n \"depositDescription\": \"Deposit via this gateway\",\n \"withdrawDescription\": \"Withdraw via this gateway\",\n \"language\": \"en\"\n }\n]" }, "headers": [ { "name": "Content-Type", "value": "application/json" } ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } }, - { "_id": "req_loc_gateway_delete", "_type": "request", "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/gateway/{gatewayUuid}/localization/{id}", "method": "DELETE", "description": "Path: gatewayUuid, id (int64). Deletes one gateway localization.", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization/{{ _['id'] }}", "headers": [ ], "authentication": { "type": "bearer", "disabled": false, "token": "{{_['admin-token']}}", "prefix": "" } } + { + "_id": "fld_api_opex_rest", + "_type": "request_group", + "parentId": "wrk_opex", + "name": "api-ports / api-opex-rest" + }, + { + "_id": "fld_addressbook", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Address Book" + }, + { + "_id": "req_addr_add", + "_type": "request", + "parentId": "fld_addressbook", + "name": "POST /opex/v1/address-book", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is implemented as string, not a strict enum in AddAddressBookItemRequest.\n- Known examples: CRYPTO, BANK.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/address-book", + "body": { + "mimeType": "application/json", + "text": "{\n \"name\": \"Home Wallet\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_addr_list", + "_type": "request", + "parentId": "fld_addressbook", + "name": "GET /opex/v1/address-book", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nResponse 200: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n }\n]", + "url": "{{ _['api-host'] }}/opex/v1/address-book", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_addr_delete", + "_type": "request", + "parentId": "fld_addressbook", + "name": "DELETE /opex/v1/address-book/{id}", + "method": "DELETE", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_addr_update", + "_type": "request", + "parentId": "fld_addressbook", + "name": "PUT /opex/v1/address-book/{id}", + "method": "PUT", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- id: Long\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is implemented as string, not a strict enum in AddAddressBookItemRequest.\n- Known examples: CRYPTO, BANK.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", + "body": { + "mimeType": "application/json", + "text": "{\n \"name\": \"Updated Name\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_storage_admin", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Storage Admin" + }, + { + "_id": "req_storage_get", + "_type": "request", + "parentId": "fld_storage_admin", + "name": "GET /opex/v1/admin/storage", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nBinary file stream.\nContent-Type: application/octet-stream\nSchema:\n{\n \"type\": \"string\",\n \"format\": \"binary\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/admin/storage", + "parameters": [ + { + "name": "bucket", + "value": "{{ _['bucket'] }}", + "description": "Bucket name" + }, + { + "name": "key", + "value": "{{ _['key'] }}", + "description": "Object key" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_storage_post", + "_type": "request", + "parentId": "fld_storage_admin", + "name": "POST /opex/v1/admin/storage", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- bucket: string\n- key: string\n- isPublic: boolean | null, default false\n\nMultipart form-data parts:\n- file: binary file\n\nResponse 200: string\nExample:\n\"http://localhost:8094/opex/v1/storage?bucket=public&key=logo.png\"", + "url": "{{ _['api-host'] }}/opex/v1/admin/storage", + "parameters": [ + { + "name": "bucket", + "value": "{{ _['bucket'] }}", + "description": "Bucket name" + }, + { + "name": "key", + "value": "{{ _['key'] }}", + "description": "Object key" + }, + { + "name": "isPublic", + "value": "false", + "description": "Publicly accessible if true" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + }, + "body": { + "mimeType": "multipart/form-data", + "params": [ + { + "name": "file", + "type": "file", + "fileName": "/path/to/file.png" + } + ], + "paramsOrder": [ + "file" + ] + } + }, + { + "_id": "req_storage_delete", + "_type": "request", + "parentId": "fld_storage_admin", + "name": "DELETE /opex/v1/admin/storage", + "method": "DELETE", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/admin/storage", + "parameters": [ + { + "name": "bucket", + "value": "{{ _['bucket'] }}", + "description": "Bucket name" + }, + { + "name": "key", + "value": "{{ _['key'] }}", + "description": "Object key" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_withdraw", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Withdraw" + }, + { + "_id": "req_withdraw_post", + "_type": "request", + "parentId": "fld_withdraw", + "name": "POST /opex/v1/withdraw", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_withdraw:write.\n- Insomnia token: {{ _['user-token'] }}.\n- Security matcher: POST /opex/v1/withdraw.\n\nRequest body: RequestWithdrawBody\n{\n \"currency\": \"string\",\n \"amount\": \"BigDecimal\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"gatewayUuid\": \"string | null\"\n}\n\nResponse 200: WithdrawActionResult | null\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", + "url": "{{ _['api-host'] }}/opex/v1/withdraw", + "body": { + "mimeType": "application/json", + "text": "{\n \"currency\": \"USDT\",\n \"amount\": 50.00,\n \"destSymbol\": null,\n \"destAddress\": \"0x...\",\n \"destNetwork\": null,\n \"destNote\": null,\n \"gatewayUuid\": null\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_withdraw_cancel", + "_type": "request", + "parentId": "fld_withdraw", + "name": "PUT /opex/v1/withdraw/{withdrawUuid}/cancel", + "method": "PUT", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only for this exact URL, because the config only defines PUT /opex/v1/withdraw, not PUT /opex/v1/withdraw/{withdrawUuid}/cancel.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n- Review note: if cancel should require withdraw permission, add a matcher such as PUT /opex/v1/withdraw/** with PERM_withdraw:write.\n\nPath params:\n- withdrawUuid: string\n\nResponse 200:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/cancel", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_withdraw_find", + "_type": "request", + "parentId": "fld_withdraw", + "name": "GET /opex/v1/withdraw/{withdrawUuid}", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific GET matcher is defined for /opex/v1/withdraw/{withdrawUuid}.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- withdrawUuid: string\n\nResponse 200: WithdrawResponse\n{\n \"withdrawId\": \"string\",\n \"uuid\": \"string\",\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"appliedFee\": \"BigDecimal\",\n \"destAmount\": \"BigDecimal | null\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string | null\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"destTransactionRef\": \"string | null\",\n \"statusReason\": \"string | null\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"applicator\": \"string | null\",\n \"withdrawType\": \"CARD_TO_CARD | SHEBA | ON_CHAIN | OFF_CHAIN\",\n \"attachment\": \"string | null\",\n \"createDate\": \"LocalDateTime\",\n \"lastUpdateDate\": \"LocalDateTime | null\",\n \"transferMethod\": \"CARD | SHEBA | IPG | EXCHANGE | MANUALLY | VOUCHER | MPG | REWARD | null\",\n \"otpRequired\": \"integer | null\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_withdraw_otp_req", + "_type": "request", + "parentId": "fld_withdraw", + "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only for this exact URL, because the config only defines POST /opex/v1/withdraw, not POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nResponse 200: TempOtpResponse\n{\n \"otp\": \"string | null\",\n \"receivers\": [\n {\n \"receiver\": \"string\",\n \"type\": \"SMS | EMAIL\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/request", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_withdraw_otp_verify", + "_type": "request", + "parentId": "fld_withdraw", + "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only for this exact URL, because the config only defines POST /opex/v1/withdraw, not POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nQuery params:\n- otpCode: string\n\nResponse 200: WithdrawActionResult\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", + "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/verify", + "parameters": [ + { + "name": "otpCode", + "value": "{{ _['otpCode'] }}", + "description": "OTP code" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_deposit", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Deposit" + }, + { + "_id": "req_deposit_post", + "_type": "request", + "parentId": "fld_deposit", + "name": "POST /opex/v1/deposit", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_deposit:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_deposit:write.\n- Security matcher: /opex/v1/deposit/**.\n\nRequest body: RequestDepositBody\n{\n \"symbol\": \"string\",\n \"receiverUuid\": \"string\",\n \"receiverWalletType\": \"WalletType\",\n \"amount\": \"BigDecimal\",\n \"description\": \"string | null\",\n \"transferRef\": \"string | null\",\n \"gatewayUuid\": \"string | null\",\n \"chain\": \"string | null\"\n}\n\nNotes:\n- receiverWalletType uses WalletType. The current request DTO references WalletType, but this collection does not lock specific enum values.\n\nResponse 200: TransferResult | null\n{\n \"date\": \"Long\",\n \"sourceUuid\": \"string\",\n \"sourceWalletType\": \"WalletType\",\n \"sourceBalanceBeforeAction\": {\n \"currency\": {\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n },\n \"amount\": \"BigDecimal\"\n },\n \"sourceBalanceAfterAction\": Amount,\n \"amount\": Amount,\n \"destUuid\": \"string\",\n \"destWalletType\": \"WalletType\",\n \"receivedAmount\": Amount,\n \"sourceWallet\": \"Long | null\",\n \"destWallet\": \"Long | null\"\n}\n\nNested Amount:\n{\n \"currency\": CurrencyCommand,\n \"amount\": \"BigDecimal\"\n}\n\nNested CurrencyCommand:\n{\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/deposit", + "body": { + "mimeType": "application/json", + "text": "{\n \"symbol\": \"USDT\",\n \"receiverUuid\": \"{{ _['id'] }}\",\n \"receiverWalletType\": \"MAIN\",\n \"amount\": 100.00,\n \"description\": null,\n \"transferRef\": null,\n \"gatewayUuid\": null,\n \"chain\": null\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_wallet_admin", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Wallet Admin" + }, + { + "_id": "req_wallet_admin_users", + "_type": "request", + "parentId": "fld_wallet_admin", + "name": "GET /opex/v1/admin/wallet/users", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- uuid: string | null\n- currency: string | null\n- excludeSystem: boolean, default false\n- limit: integer | null, default 10\n- offset: integer | null, default 0\n\nResponse 200: List\n[\n {\n \"uuid\": \"string\",\n \"title\": \"string\",\n \"wallets\": [\n {\n \"currency\": \"string\",\n \"free\": \"double\",\n \"locked\": \"double\",\n \"pendingWithdraw\": \"double\"\n }\n ]\n }\n]", + "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users", + "parameters": [ + { + "name": "excludeSystem", + "value": "false", + "description": "Exclude system wallets" + }, + { + "name": "limit", + "value": "10", + "description": "Page size" + }, + { + "name": "offset", + "value": "0", + "description": "Page offset" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_wallet_admin_system_total", + "_type": "request", + "parentId": "fld_wallet_admin", + "name": "GET /opex/v1/admin/wallet/system/total", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nResponse 200: List\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", + "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/system/total", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_wallet_admin_users_total", + "_type": "request", + "parentId": "fld_wallet_admin", + "name": "GET /opex/v1/admin/wallet/users/total", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nResponse 200: List | null\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", + "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users/total", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_voucher", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Voucher" + }, + { + "_id": "req_voucher_put", + "_type": "request", + "parentId": "fld_voucher", + "name": "PUT /opex/v1/voucher/{code}", + "method": "PUT", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Insomnia token: {{ _['user-token'] }}.\n- Config note: SecurityConfig defines PERM_voucher:submit for /opex/v1/voucher, but this request calls /opex/v1/voucher/{code}.\n- Effective matcher for this exact URL may fall back to anyExchange().authenticated() unless the matcher is changed to /opex/v1/voucher/**.\n- Intended authority to use for voucher-submit tokens: PERM_voucher:submit.\n\nPath params:\n- code: string\n\nResponse 200: SubmitVoucherResponse\n{\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"issuer\": \"string | null\",\n \"description\": \"string | null\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/voucher/{{ _['code'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_user_data", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "User Data" + }, + { + "_id": "req_user_data_trade_volume", + "_type": "request", + "parentId": "fld_user_data", + "name": "GET /opex/v1/user/data/trade/volume", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nQuery params:\n- symbol: string, e.g. BTCUSDT\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", + "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume", + "parameters": [ + { + "name": "symbol", + "value": "{{ _['symbol'] }}", + "description": "Symbol, e.g., BTCUSDT" + }, + { + "name": "interval", + "value": "{{ _['interval'] }}", + "description": "Interval: Day | Week | Month | Year" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_user_data_trade_volume_total", + "_type": "request", + "parentId": "fld_user_data", + "name": "GET /opex/v1/user/data/trade/volume/total", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nQuery params:\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", + "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume/total", + "parameters": [ + { + "name": "interval", + "value": "{{ _['interval'] }}", + "description": "Interval: Day | Week | Month | Year" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_user_data_fee", + "_type": "request", + "parentId": "fld_user_data", + "name": "GET /opex/v1/user/data/fee", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nResponse 200: UserFee\n{\n \"name\": \"string\",\n \"makerFee\": \"BigDecimal\",\n \"takerFee\": \"BigDecimal\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/user/data/fee", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_user_data_withdraw_total", + "_type": "request", + "parentId": "fld_user_data", + "name": "GET /opex/v1/user/data/withdraw/volume/total", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nQuery params:\n- interval: string | null\n- Accepted labels map to Interval, commonly: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", + "url": "{{ _['api-host'] }}/opex/v1/user/data/withdraw/volume/total", + "parameters": [ + { + "name": "interval", + "value": "{{ _['interval'] }}", + "description": "Optional label: Day | Week | Month | Year" + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_bank_account", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Bank Account" + }, + { + "_id": "req_bank_add", + "_type": "request", + "parentId": "fld_bank_account", + "name": "POST /opex/v1/bank-account", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_bank_account:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_bank_account:write.\n- Security matcher: /opex/v1/bank-account/**.\n\nRequest body: AddBankAccountRequest\n{\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\"\n}\n\nResponse 200: BankAccountResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/bank-account", + "body": { + "mimeType": "application/json", + "text": "{\n \"name\": \"My Bank\",\n \"cardNumber\": null,\n \"iban\": \"IRxxxxxxxxxxxx\"\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_bank_list", + "_type": "request", + "parentId": "fld_bank_account", + "name": "GET /opex/v1/bank-account", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: none.\n- Required authority: permitAll for GET /opex/v1/bank-account.\n- Insomnia token: optional; the collection currently sends {{ _['user-token'] }}, but the endpoint is public according to SecurityConfig.\n- Security matcher: GET /opex/v1/bank-account.\n\nResponse 200: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n }\n]", + "url": "{{ _['api-host'] }}/opex/v1/bank-account", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "req_bank_delete", + "_type": "request", + "parentId": "fld_bank_account", + "name": "DELETE /opex/v1/bank-account/{id}", + "method": "DELETE", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_bank_account:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_bank_account:write.\n- Security matcher: /opex/v1/bank-account/**.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/bank-account/{{ _['id'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['user-token']}}", + "prefix": "" + } + }, + { + "_id": "fld_localization_admin", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "Localization Admin" + }, + { + "_id": "req_loc_currency_get", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "GET /opex/v1/admin/currency/{currency}/localization", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- currency: string\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_currency_post", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "POST /opex/v1/admin/currency/{currency}/localization", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- currency: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", + "body": { + "mimeType": "application/json", + "text": "[\n {\n \"id\": null,\n \"name\": \"USDT\",\n \"title\": \"Tether USD\",\n \"alias\": \"Tether\",\n \"description\": \"Stablecoin description\",\n \"shortDescription\": \"Stablecoin\",\n \"language\": \"en\"\n }\n]" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_currency_delete", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "DELETE /opex/v1/admin/currency/localization/{id}", + "method": "DELETE", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/admin/currency/localization/{{ _['id'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_terminal_get", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "GET /opex/v1/admin/terminal/{terminalUuid}/localization", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- terminalUuid: string\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_terminal_post", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "POST /opex/v1/admin/terminal/{terminalUuid}/localization", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- terminalUuid: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", + "body": { + "mimeType": "application/json", + "text": "[\n {\n \"id\": null,\n \"description\": \"Terminal description\",\n \"owner\": \"OPEX\",\n \"language\": \"en\"\n }\n]" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_terminal_delete", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "DELETE /opex/v1/admin/terminal/localization/{id}", + "method": "DELETE", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/localization/{{ _['id'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_gateway_get", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "GET /opex/v1/admin/gateway/{gatewayUuid}/localization", + "method": "GET", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" uses off-chain gateway localization.\n- gatewayUuid starting with \"ong\" uses on-chain gateway localization.\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_gateway_post", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "POST /opex/v1/admin/gateway/{gatewayUuid}/localization", + "method": "POST", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" saves off-chain gateway localization.\n- gatewayUuid starting with \"ong\" saves on-chain gateway localization.\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", + "body": { + "mimeType": "application/json", + "text": "[\n {\n \"id\": null,\n \"depositDescription\": \"Deposit via this gateway\",\n \"withdrawDescription\": \"Withdraw via this gateway\",\n \"language\": \"en\"\n }\n]" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_loc_gateway_delete", + "_type": "request", + "parentId": "fld_localization_admin", + "name": "DELETE /opex/v1/admin/gateway/{gatewayUuid}/localization/{id}", + "method": "DELETE", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- gatewayUuid: string\n- id: Long\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" deletes off-chain gateway localization.\n- gatewayUuid starting with \"ong\" deletes on-chain gateway localization.\n\nResponse 200:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization/{{ _['id'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + } ] } diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt new file mode 100644 index 000000000..ca6902160 --- /dev/null +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt @@ -0,0 +1,37 @@ +package co.nilin.opex.api.app.config + +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.info.License +import io.swagger.v3.oas.models.security.SecurityScheme +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class OpenApiConfig { + + @Bean + fun opexOpenApi(): OpenAPI { + return OpenAPI() + .info( + Info() + .title("Opex API") + .description("OpenAPI documentation for Opex REST APIs.") + .version("1.0.1-beta.7") + .description("Backend for opex exchange.") + ) + .components( + Components() + .addSecuritySchemes( + "bearerAuth", + SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .description("JWT Bearer token") + ) + ) + } +} + diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/SwaggerConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/SwaggerConfig.kt deleted file mode 100644 index 68723c02a..000000000 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/SwaggerConfig.kt +++ /dev/null @@ -1,96 +0,0 @@ -package co.nilin.opex.api.app.config - -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.security.core.annotation.AuthenticationPrincipal -import springfox.documentation.builders.ApiInfoBuilder -import springfox.documentation.builders.OAuthBuilder -import springfox.documentation.builders.PathSelectors -import springfox.documentation.builders.RequestParameterBuilder -import springfox.documentation.service.* -import springfox.documentation.spi.DocumentationType -import springfox.documentation.spi.service.contexts.SecurityContext -import springfox.documentation.spring.web.plugins.Docket -import springfox.documentation.swagger.web.SecurityConfiguration -import springfox.documentation.swagger.web.SecurityConfigurationBuilder -import java.security.Principal -import java.util.* - -@Configuration -class SwaggerConfig { - @Value("\${swagger.authUrl}") - private lateinit var authUrl: String - - @Bean - fun opexApi(): Docket { - return Docket(DocumentationType.SWAGGER_2) - .groupName("opex-api") - .apiInfo(apiInfo()) - .select() - .paths(PathSelectors.regex("^/api/v3.*")) - .build() - .globalRequestParameters( - Collections.singletonList( - RequestParameterBuilder() - .name("content-type") - .description("content-type") - .`in`(ParameterType.HEADER) - .required(true) - .build() - ) - ) - .ignoredParameterTypes(AuthenticationPrincipal::class.java, Principal::class.java) - .useDefaultResponseMessages(false) - .securitySchemes(Collections.singletonList(oauth())) - .securityContexts(Collections.singletonList(securityContext())) - } - - private fun apiInfo(): ApiInfo { - return ApiInfoBuilder() - .title("OPEX API") - .description("Backend for opex exchange.") - .license("MIT License") - .licenseUrl("https://github.com/opexdev/Back-end/blob/feature/1-MVP/LICENSE") - .version("0.1") - .build() - } - - private fun oauth(): SecurityScheme { - return OAuthBuilder() - .name("opex") - .grantTypes(grantTypes()) - .scopes(scopes()) - .build() - } - - private fun scopes(): List { - return listOf(AuthorizationScope("openid", "OpenId")) - } - - private fun grantTypes(): List { - val grantType = ResourceOwnerPasswordCredentialsGrant(authUrl) - return Collections.singletonList(grantType) - } - - private fun securityContext(): SecurityContext { - val securityReference = SecurityReference.builder() - .reference("opex") - .scopes(emptyArray()) - .build() - return SecurityContext.builder() - .securityReferences(Collections.singletonList(securityReference)) - .operationSelector { true } - .build() - } - - @Bean - fun securityInfo(): SecurityConfiguration { - return SecurityConfigurationBuilder.builder() - .clientId("admin-cli") - .realm("opex") - .appName("opex") - .scopeSeparator(",") - .build() - } -} diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index a3faf1697..8aa13219b 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -145,14 +145,19 @@ app: api: crypto: key: ${api_crypto_key:0e1fd29572ec8c85970d76e3433e96ee} -swagger: - authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token # --- Swagger / SpringDoc (env-driven) --- springdoc: api-docs: enabled: ${SWAGGER_API_DOCS_ENABLED:false} + path: ${SWAGGER_API_DOCS_PATH:/v3/api-docs} + swagger-ui: enabled: ${SWAGGER_UI_ENABLED:false} path: ${SWAGGER_UI_PATH:/swagger-ui.html} + try-it-out-enabled: ${SWAGGER_TRY_IT_OUT_ENABLED:true} + persist-authorization: ${SWAGGER_PERSIST_AUTHORIZATION:true} + display-request-duration: true + operations-sorter: method + tags-sorter: alpha diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt index b4c91df93..232aaa0a5 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt @@ -25,15 +25,31 @@ class SecurityConfig( @Value("\${app.auth.cert-url}") private val certUrl: String, @Value("\${app.auth.iss-url}") - private val issUrl: String + private val issUrl: String, ) { + @Value("\${swagger.auth.enabled:false}") + private var swaggerAuthEnabled: Boolean = false + + @Value("\${swagger.auth.authority:ROLE_admin}") + private lateinit var swaggerAuthority: String @Bean fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + val swaggerPaths = arrayOf( + "/swagger-ui.html", + "/swagger-ui/**", + "/v3/api-docs", + "/v3/api-docs/**", + "/webjars/**" + ) return http.csrf { it.disable() } .authorizeExchange { + if (swaggerAuthEnabled) { + it.pathMatchers(*swaggerPaths).hasAuthority(swaggerAuthority) + } else { + it.pathMatchers(*swaggerPaths).permitAll() + } it.pathMatchers("/actuator/**").permitAll() - .pathMatchers("/swagger-ui.html").permitAll() .pathMatchers("/v1/rate-limit").hasAuthority("ROLE_admin") .pathMatchers("/v2/api-docs").permitAll() .pathMatchers("/v3/depth").permitAll() diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt index 4acfeb6d3..01af12521 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement @@ -20,7 +21,10 @@ import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/bank-account") -@Tag(name = "Bank Account", description = "Manage user bank accounts") +@Tag( + name = "Bank Account", + description = "Manage authenticated user's bank accounts." +) class BankAccountController( val profileProxy: ProfileProxy, ) { @@ -28,15 +32,85 @@ class BankAccountController( @PostMapping @Operation( summary = "Add bank account", + description = """ +Creates a new bank account for the authenticated user. + +Required authentication: +- Bearer JWT +- Required authority: PERM_bank_account:write + +Request body: AddBankAccountRequest +- name: string, nullable +- cardNumber: string, nullable +- iban: string, nullable + +Response body: BankAccountResponse +- id: Long, nullable +- name: string, nullable +- cardNumber: string, nullable +- iban: string, nullable +- accountNumber: string, nullable +- bank: string, nullable +- status: WAITING | VERIFIED | REJECTED + """, security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, - content = [Content(mediaType = "application/json", schema = Schema(implementation = AddBankAccountRequest::class))] + description = "Bank account creation payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = AddBankAccountRequest::class), + examples = [ + ExampleObject( + name = "Add bank account request", + value = """ +{ + "name": "My Bank Account", + "cardNumber": "6037991234567890", + "iban": "IR123456789012345678901234" +} + """ + ) + ] + ) + ] ), responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class)) - ]) + ApiResponse( + responseCode = "200", + description = "Bank account created successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = BankAccountResponse::class), + examples = [ + ExampleObject( + name = "Bank account response", + value = """ +{ + "id": 1, + "name": "My Bank Account", + "cardNumber": "6037991234567890", + "iban": "IR123456789012345678901234", + "accountNumber": null, + "bank": null, + "status": "WAITING" +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired." + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: PERM_bank_account:write." + ) ] ) suspend fun addBankAccount( @@ -49,25 +123,107 @@ class BankAccountController( @GetMapping @Operation( summary = "List bank accounts", + description = """ +Returns bank accounts for the authenticated user. + +Required authentication: +- Bearer JWT + +Response body: Array +Each item: +- id: Long, nullable +- name: string, nullable +- cardNumber: string, nullable +- iban: string, nullable +- accountNumber: string, nullable +- bank: string, nullable +- status: WAITING | VERIFIED | REJECTED + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class))) - ]) + ApiResponse( + responseCode = "200", + description = "Bank accounts returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema( + schema = Schema(implementation = BankAccountResponse::class) + ), + examples = [ + ExampleObject( + name = "Bank account list response", + value = """ +[ + { + "id": 1, + "name": "My Bank Account", + "cardNumber": "6037991234567890", + "iban": "IR123456789012345678901234", + "accountNumber": null, + "bank": null, + "status": "WAITING" + } +] + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired." + ) ] ) - suspend fun getBankAccounts(@CurrentSecurityContext securityContext: SecurityContext): List { + suspend fun getBankAccounts( + @CurrentSecurityContext securityContext: SecurityContext + ): List { return profileProxy.getBankAccounts(securityContext.jwtAuthentication().tokenValue()) } @DeleteMapping("/{id}") @Operation( summary = "Delete bank account", + description = """ +Deletes one bank account by ID for the authenticated user. + +Required authentication: +- Bearer JWT +- Required authority: PERM_bank_account:write + +Path parameters: +- id: Bank account ID. + +Response body: +- No response body. + """, security = [SecurityRequirement(name = "bearerAuth")], parameters = [ - Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) + Parameter( + name = "id", + `in` = ParameterIn.PATH, + required = true, + description = "Bank account ID.", + schema = Schema(type = "integer", format = "int64"), + example = "1" + ) ], - responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + responses = [ + ApiResponse( + responseCode = "200", + description = "Bank account deleted successfully. No response body." + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired." + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: PERM_bank_account:write." + ) + ] ) suspend fun deleteBankAccount( @PathVariable("id") id: Long, @@ -75,6 +231,4 @@ class BankAccountController( ) { profileProxy.deleteBankAccount(securityContext.jwtAuthentication().tokenValue(), id) } - - } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b9078536e..5c8276f04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -493,6 +493,10 @@ services: - TOTAL_ASSET_CALCULATION_CURRENCY=${TOTAL_ASSET_CALCULATION_CURRENCY} - TOKEN_ISSUER_URL=${KC_ISSUER_URL} - APP_BASE_URL=${APP_BASE_URL} + - SWAGGER_API_DOCS_ENABLED=${SWAGGER_API_DOCS_ENABLED} + - SWAGGER_UI_ENABLED=${SWAGGER_UI_ENABLED} + - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} + - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} depends_on: - consul - vault From 260077a7b5b568eeee6af11b9ddca550f54db5e6 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 11 May 2026 16:10:02 +0330 Subject: [PATCH 05/56] Update swagger dependencies --- api/api-app/pom.xml | 6 +--- .../ports/binance/config/SecurityConfig.kt | 30 ++++++++++++++++--- api/api-ports/api-opex-rest/pom.xml | 5 ++-- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/api/api-app/pom.xml b/api/api-app/pom.xml index 164918767..07c13842b 100644 --- a/api/api-app/pom.xml +++ b/api/api-app/pom.xml @@ -60,11 +60,7 @@ co.nilin.opex.api.ports.postgres api-persister-postgres - - io.springfox - springfox-boot-starter - 3.0.0 - + org.springframework.cloud spring-cloud-starter-vault-config diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt index 232aaa0a5..bb19f7d59 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt @@ -6,6 +6,7 @@ import co.nilin.opex.common.security.ReactiveCustomJwtConverter import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.core.annotation.Order import org.springframework.http.HttpMethod import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity import org.springframework.security.config.web.server.SecurityWebFiltersOrder @@ -15,6 +16,7 @@ import org.springframework.security.oauth2.jwt.JwtValidators import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder import org.springframework.security.web.server.SecurityWebFilterChain +import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers import org.springframework.web.reactive.function.client.WebClient import org.springframework.web.server.WebFilter @@ -34,7 +36,8 @@ class SecurityConfig( private lateinit var swaggerAuthority: String @Bean - fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + @Order(0) + fun swaggerSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { val swaggerPaths = arrayOf( "/swagger-ui.html", "/swagger-ui/**", @@ -42,13 +45,31 @@ class SecurityConfig( "/v3/api-docs/**", "/webjars/**" ) - return http.csrf { it.disable() } + + return http + .securityMatcher(ServerWebExchangeMatchers.pathMatchers(*swaggerPaths)) + .csrf { it.disable() } .authorizeExchange { if (swaggerAuthEnabled) { - it.pathMatchers(*swaggerPaths).hasAuthority(swaggerAuthority) + it.anyExchange().hasAuthority(swaggerAuthority) } else { - it.pathMatchers(*swaggerPaths).permitAll() + it.anyExchange().permitAll() + } + } + .oauth2ResourceServer { + it.jwt { jwt -> + jwt.jwtAuthenticationConverter(ReactiveCustomJwtConverter()) } + } + .build() + } + + @Bean + @Order(1) + fun apiSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + + return http.csrf { it.disable() } + .authorizeExchange { it.pathMatchers("/actuator/**").permitAll() .pathMatchers("/v1/rate-limit").hasAuthority("ROLE_admin") .pathMatchers("/v2/api-docs").permitAll() @@ -114,4 +135,5 @@ class SecurityConfig( return decoder } + } diff --git a/api/api-ports/api-opex-rest/pom.xml b/api/api-ports/api-opex-rest/pom.xml index 7c2a9442b..7f4aa6250 100644 --- a/api/api-ports/api-opex-rest/pom.xml +++ b/api/api-ports/api-opex-rest/pom.xml @@ -66,7 +66,6 @@ reactor-test test - io.swagger.core.v3 swagger-annotations @@ -75,8 +74,8 @@ org.springdoc - springdoc-openapi-webflux-ui - 1.7.0 + springdoc-openapi-starter-webflux-ui + 2.8.17 From 89176a8c905eeccb6571754610194832cf13e244 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 11 May 2026 20:44:39 +0330 Subject: [PATCH 06/56] Complete swagger description about bank account services --- Insomnia_2026-05-10.json | 2 +- .../opex/api/app/config/OpenApiConfig.kt | 1 - .../src/main/resources/application.yml | 1 + .../ports/binance/config/SecurityConfig.kt | 2 +- api/api-ports/api-opex-rest/pom.xml | 9 +------ .../opex/controller/BankAccountController.kt | 24 +++++++++++++------ .../api/ports/proxy/impl/ProfileProxyImpl.kt | 2 +- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Insomnia_2026-05-10.json b/Insomnia_2026-05-10.json index 4a307ea93..b667392a0 100644 --- a/Insomnia_2026-05-10.json +++ b/Insomnia_2026-05-10.json @@ -576,7 +576,7 @@ "parentId": "fld_bank_account", "name": "POST /opex/v1/bank-account", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_bank_account:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_bank_account:write.\n- Security matcher: /opex/v1/bank-account/**.\n\nRequest body: AddBankAccountRequest\n{\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\"\n}\n\nResponse 200: BankAccountResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n}", + "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_bank_account:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_bank_account:write.\n - Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid.\n- Security matcher: /opex/v1/bank-account/**.\n\nRequest body: AddBankAccountRequest\n{\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\"\n}\n\nResponse 200: BankAccountResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n}", "url": "{{ _['api-host'] }}/opex/v1/bank-account", "body": { "mimeType": "application/json", diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt index ca6902160..b5713baec 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt @@ -3,7 +3,6 @@ package co.nilin.opex.api.app.config import io.swagger.v3.oas.models.Components import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.info.Info -import io.swagger.v3.oas.models.info.License import io.swagger.v3.oas.models.security.SecurityScheme import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 8aa13219b..959728189 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -161,3 +161,4 @@ springdoc: display-request-duration: true operations-sorter: method tags-sorter: alpha +spring.mvc.pathmatch.matching-strategy: ANT_PATH_MATCHER diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt index bb19f7d59..120ebaf86 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt @@ -102,7 +102,7 @@ class SecurityConfig( .pathMatchers(HttpMethod.PUT, "/opex/v1/otc/rate").hasAnyAuthority("ROLE_admin", "ROLE_rate_bot") .pathMatchers(HttpMethod.GET, "/opex/v1/otc/**").permitAll() .pathMatchers("/opex/v1/otc/**").hasAuthority("ROLE_admin") - .pathMatchers(HttpMethod.GET, "/opex/v1/bank-account").permitAll() + .pathMatchers(HttpMethod.GET, "/opex/v1/bank-account").authenticated() .pathMatchers("/opex/v1/bank-account/**").hasAuthority("PERM_bank_account:write") .anyExchange().authenticated() } diff --git a/api/api-ports/api-opex-rest/pom.xml b/api/api-ports/api-opex-rest/pom.xml index 7f4aa6250..22b37a60d 100644 --- a/api/api-ports/api-opex-rest/pom.xml +++ b/api/api-ports/api-opex-rest/pom.xml @@ -66,19 +66,12 @@ reactor-test test - - io.swagger.core.v3 - swagger-annotations - 2.2.15 - - org.springdoc springdoc-openapi-starter-webflux-ui - 2.8.17 + 2.8.14 - central diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt index 01af12521..c03bbae3b 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -44,6 +44,7 @@ Request body: AddBankAccountRequest - cardNumber: string, nullable - iban: string, nullable + Response body: BankAccountResponse - id: Long, nullable - name: string, nullable @@ -56,7 +57,7 @@ Response body: BankAccountResponse security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, - description = "Bank account creation payload.", + description = "Bank account creation payload, Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid.", content = [ Content( mediaType = "application/json", @@ -68,7 +69,7 @@ Response body: BankAccountResponse { "name": "My Bank Account", "cardNumber": "6037991234567890", - "iban": "IR123456789012345678901234" + "iban": null } """ ) @@ -105,16 +106,20 @@ Response body: BankAccountResponse ), ApiResponse( responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired." + description = "Unauthorized. Bearer token is missing, invalid, or expired.", + content = [Content()] + ), ApiResponse( responseCode = "403", - description = "Forbidden. Required authority is missing: PERM_bank_account:write." + description = "Forbidden. Required authority is missing: PERM_bank_account:write.", + content = [Content()] ) ] ) suspend fun addBankAccount( @RequestBody request: AddBankAccountRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): BankAccountResponse { return profileProxy.addBankAccount(securityContext.jwtAuthentication().tokenValue(), request) @@ -173,11 +178,13 @@ Each item: ), ApiResponse( responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired." + description = "Unauthorized. Bearer token is missing, invalid, or expired.", + content = [Content()] ) ] ) suspend fun getBankAccounts( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): List { return profileProxy.getBankAccounts(securityContext.jwtAuthentication().tokenValue()) @@ -217,16 +224,19 @@ Response body: ), ApiResponse( responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired." + description = "Unauthorized. Bearer token is missing, invalid, or expired.", + content = [Content()] ), ApiResponse( responseCode = "403", - description = "Forbidden. Required authority is missing: PERM_bank_account:write." + description = "Forbidden. Required authority is missing: PERM_bank_account:write.", + content = [Content()] ) ] ) suspend fun deleteBankAccount( @PathVariable("id") id: Long, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ) { profileProxy.deleteBankAccount(securityContext.jwtAuthentication().tokenValue(), id) diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt index 68dd031c8..981ff3c59 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt @@ -188,7 +188,7 @@ class ProfileProxyImpl(@Qualifier("generalWebClient") private val webClient: Web override suspend fun getBankAccounts(token: String): List { return webClient.get() - .uri("$baseUrl/bank-account`") + .uri("$baseUrl/bank-account") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() From d15f971c935eec5f6547dae91dea3e103ffa3c42 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 11 May 2026 21:44:24 +0330 Subject: [PATCH 07/56] Complete insomnia data about bank account services --- Insomnia_2026-05-10.json | 72 ++--- .../opex/controller/AddressBookController.kt | 256 ++++++++++++++++-- .../api/ports/proxy/impl/ProfileProxyImpl.kt | 2 +- 3 files changed, 273 insertions(+), 57 deletions(-) diff --git a/Insomnia_2026-05-10.json b/Insomnia_2026-05-10.json index b667392a0..05ebd03ec 100644 --- a/Insomnia_2026-05-10.json +++ b/Insomnia_2026-05-10.json @@ -58,11 +58,11 @@ "parentId": "fld_addressbook", "name": "POST /opex/v1/address-book", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is implemented as string, not a strict enum in AddAddressBookItemRequest.\n- Known examples: CRYPTO, BANK.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is a server-provided string value.\n- Clients should use the exact value returned by the related chain/address-type source service.\n- Do not treat addressType as a fixed enum and do not hardcode a static value list.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nResponse 401:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/address-book", "body": { "mimeType": "application/json", - "text": "{\n \"name\": \"Home Wallet\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" + "text": "{\n \"name\": \"Home Wallet\",\n \"address\": \"0x...\",\n \"addressType\": \"ethereum\"\n}" }, "headers": [ { @@ -83,7 +83,7 @@ "parentId": "fld_addressbook", "name": "GET /opex/v1/address-book", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nResponse 200: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n }\n]", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nResponse 200: Array\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n }\n]\n\nResponse 401:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/address-book", "headers": [], "authentication": { @@ -99,7 +99,7 @@ "parentId": "fld_addressbook", "name": "DELETE /opex/v1/address-book/{id}", "method": "DELETE", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.\n\nResponse 401:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", "headers": [], "authentication": { @@ -115,11 +115,11 @@ "parentId": "fld_addressbook", "name": "PUT /opex/v1/address-book/{id}", "method": "PUT", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/address-book.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- id: Long\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is implemented as string, not a strict enum in AddAddressBookItemRequest.\n- Known examples: CRYPTO, BANK.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nPath params:\n- id: Long\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is a server-provided string value.\n- Clients should use the exact value returned by the related chain/address-type source service.\n- Do not treat addressType as a fixed enum and do not hardcode a static value list.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nResponse 401:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", "body": { "mimeType": "application/json", - "text": "{\n \"name\": \"Updated Name\",\n \"address\": \"0x...\",\n \"addressType\": \"CRYPTO\"\n}" + "text": "{\n \"name\": \"Updated Name\",\n \"address\": \"0x...\",\n \"addressType\": \"ethereum\"\n}" }, "headers": [ { @@ -146,7 +146,7 @@ "parentId": "fld_storage_admin", "name": "GET /opex/v1/admin/storage", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nBinary file stream.\nContent-Type: application/octet-stream\nSchema:\n{\n \"type\": \"string\",\n \"format\": \"binary\"\n}", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nBinary file stream.\nContent-Type: application/octet-stream\nSchema:\n{\n \"type\": \"string\",\n \"format\": \"binary\"\n}", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { @@ -174,7 +174,7 @@ "parentId": "fld_storage_admin", "name": "POST /opex/v1/admin/storage", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- bucket: string\n- key: string\n- isPublic: boolean | null, default false\n\nMultipart form-data parts:\n- file: binary file\n\nResponse 200: string\nExample:\n\"http://localhost:8094/opex/v1/storage?bucket=public&key=logo.png\"", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- bucket: string\n- key: string\n- isPublic: boolean | null, default false\n\nMultipart form-data parts:\n- file: binary file\n\nResponse 200: string\nExample:\n\"http://localhost:8094/opex/v1/storage?bucket=public&key=logo.png\"", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { @@ -220,7 +220,7 @@ "parentId": "fld_storage_admin", "name": "DELETE /opex/v1/admin/storage", "method": "DELETE", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nNo response body.", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/admin/storage", "parameters": [ { @@ -254,7 +254,7 @@ "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_withdraw:write.\n- Insomnia token: {{ _['user-token'] }}.\n- Security matcher: POST /opex/v1/withdraw.\n\nRequest body: RequestWithdrawBody\n{\n \"currency\": \"string\",\n \"amount\": \"BigDecimal\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"gatewayUuid\": \"string | null\"\n}\n\nResponse 200: WithdrawActionResult | null\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", + "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_withdraw:write.\n\nRequest body: RequestWithdrawBody\n{\n \"currency\": \"string\",\n \"amount\": \"BigDecimal\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"gatewayUuid\": \"string | null\"\n}\n\nResponse 200: WithdrawActionResult | null\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", "url": "{{ _['api-host'] }}/opex/v1/withdraw", "body": { "mimeType": "application/json", @@ -279,7 +279,7 @@ "parentId": "fld_withdraw", "name": "PUT /opex/v1/withdraw/{withdrawUuid}/cancel", "method": "PUT", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only for this exact URL, because the config only defines PUT /opex/v1/withdraw, not PUT /opex/v1/withdraw/{withdrawUuid}/cancel.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n- Review note: if cancel should require withdraw permission, add a matcher such as PUT /opex/v1/withdraw/** with PERM_withdraw:write.\n\nPath params:\n- withdrawUuid: string\n\nResponse 200:\nNo response body.", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n\nResponse 200:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/cancel", "headers": [], "authentication": { @@ -295,7 +295,7 @@ "parentId": "fld_withdraw", "name": "GET /opex/v1/withdraw/{withdrawUuid}", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific GET matcher is defined for /opex/v1/withdraw/{withdrawUuid}.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- withdrawUuid: string\n\nResponse 200: WithdrawResponse\n{\n \"withdrawId\": \"string\",\n \"uuid\": \"string\",\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"appliedFee\": \"BigDecimal\",\n \"destAmount\": \"BigDecimal | null\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string | null\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"destTransactionRef\": \"string | null\",\n \"statusReason\": \"string | null\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"applicator\": \"string | null\",\n \"withdrawType\": \"CARD_TO_CARD | SHEBA | ON_CHAIN | OFF_CHAIN\",\n \"attachment\": \"string | null\",\n \"createDate\": \"LocalDateTime\",\n \"lastUpdateDate\": \"LocalDateTime | null\",\n \"transferMethod\": \"CARD | SHEBA | IPG | EXCHANGE | MANUALLY | VOUCHER | MPG | REWARD | null\",\n \"otpRequired\": \"integer | null\"\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n\nResponse 200: WithdrawResponse\n{\n \"withdrawId\": \"string\",\n \"uuid\": \"string\",\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"appliedFee\": \"BigDecimal\",\n \"destAmount\": \"BigDecimal | null\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string | null\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"destTransactionRef\": \"string | null\",\n \"statusReason\": \"string | null\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"applicator\": \"string | null\",\n \"withdrawType\": \"CARD_TO_CARD | SHEBA | ON_CHAIN | OFF_CHAIN\",\n \"attachment\": \"string | null\",\n \"createDate\": \"LocalDateTime\",\n \"lastUpdateDate\": \"LocalDateTime | null\",\n \"transferMethod\": \"CARD | SHEBA | IPG | EXCHANGE | MANUALLY | VOUCHER | MPG | REWARD | null\",\n \"otpRequired\": \"integer | null\"\n}", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}", "headers": [], "authentication": { @@ -311,7 +311,7 @@ "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only for this exact URL, because the config only defines POST /opex/v1/withdraw, not POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nResponse 200: TempOtpResponse\n{\n \"otp\": \"string | null\",\n \"receivers\": [\n {\n \"receiver\": \"string\",\n \"type\": \"SMS | EMAIL\"\n }\n ]\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nResponse 200: TempOtpResponse\n{\n \"otp\": \"string | null\",\n \"receivers\": [\n {\n \"receiver\": \"string\",\n \"type\": \"SMS | EMAIL\"\n }\n ]\n}", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/request", "headers": [], "authentication": { @@ -327,7 +327,7 @@ "parentId": "fld_withdraw", "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only for this exact URL, because the config only defines POST /opex/v1/withdraw, not POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nQuery params:\n- otpCode: string\n\nResponse 200: WithdrawActionResult\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nQuery params:\n- otpCode: string\n\nResponse 200: WithdrawActionResult\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/verify", "parameters": [ { @@ -356,7 +356,7 @@ "parentId": "fld_deposit", "name": "POST /opex/v1/deposit", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_deposit:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_deposit:write.\n- Security matcher: /opex/v1/deposit/**.\n\nRequest body: RequestDepositBody\n{\n \"symbol\": \"string\",\n \"receiverUuid\": \"string\",\n \"receiverWalletType\": \"WalletType\",\n \"amount\": \"BigDecimal\",\n \"description\": \"string | null\",\n \"transferRef\": \"string | null\",\n \"gatewayUuid\": \"string | null\",\n \"chain\": \"string | null\"\n}\n\nNotes:\n- receiverWalletType uses WalletType. The current request DTO references WalletType, but this collection does not lock specific enum values.\n\nResponse 200: TransferResult | null\n{\n \"date\": \"Long\",\n \"sourceUuid\": \"string\",\n \"sourceWalletType\": \"WalletType\",\n \"sourceBalanceBeforeAction\": {\n \"currency\": {\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n },\n \"amount\": \"BigDecimal\"\n },\n \"sourceBalanceAfterAction\": Amount,\n \"amount\": Amount,\n \"destUuid\": \"string\",\n \"destWalletType\": \"WalletType\",\n \"receivedAmount\": Amount,\n \"sourceWallet\": \"Long | null\",\n \"destWallet\": \"Long | null\"\n}\n\nNested Amount:\n{\n \"currency\": CurrencyCommand,\n \"amount\": \"BigDecimal\"\n}\n\nNested CurrencyCommand:\n{\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_deposit:write.\n\nRequest body: RequestDepositBody\n{\n \"symbol\": \"string\",\n \"receiverUuid\": \"string\",\n \"receiverWalletType\": \"WalletType\",\n \"amount\": \"BigDecimal\",\n \"description\": \"string | null\",\n \"transferRef\": \"string | null\",\n \"gatewayUuid\": \"string | null\",\n \"chain\": \"string | null\"\n}\n\nNotes:\n- receiverWalletType uses WalletType. The current request DTO references WalletType, but this collection does not lock specific enum values.\n\nResponse 200: TransferResult | null\n{\n \"date\": \"Long\",\n \"sourceUuid\": \"string\",\n \"sourceWalletType\": \"WalletType\",\n \"sourceBalanceBeforeAction\": {\n \"currency\": {\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n },\n \"amount\": \"BigDecimal\"\n },\n \"sourceBalanceAfterAction\": Amount,\n \"amount\": Amount,\n \"destUuid\": \"string\",\n \"destWalletType\": \"WalletType\",\n \"receivedAmount\": Amount,\n \"sourceWallet\": \"Long | null\",\n \"destWallet\": \"Long | null\"\n}\n\nNested Amount:\n{\n \"currency\": CurrencyCommand,\n \"amount\": \"BigDecimal\"\n}\n\nNested CurrencyCommand:\n{\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n}", "url": "{{ _['api-host'] }}/opex/v1/deposit", "body": { "mimeType": "application/json", @@ -387,7 +387,7 @@ "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/users", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nQuery params:\n- uuid: string | null\n- currency: string | null\n- excludeSystem: boolean, default false\n- limit: integer | null, default 10\n- offset: integer | null, default 0\n\nResponse 200: List\n[\n {\n \"uuid\": \"string\",\n \"title\": \"string\",\n \"wallets\": [\n {\n \"currency\": \"string\",\n \"free\": \"double\",\n \"locked\": \"double\",\n \"pendingWithdraw\": \"double\"\n }\n ]\n }\n]", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- uuid: string | null\n- currency: string | null\n- excludeSystem: boolean, default false\n- limit: integer | null, default 10\n- offset: integer | null, default 0\n\nResponse 200: List\n[\n {\n \"uuid\": \"string\",\n \"title\": \"string\",\n \"wallets\": [\n {\n \"currency\": \"string\",\n \"free\": \"double\",\n \"locked\": \"double\",\n \"pendingWithdraw\": \"double\"\n }\n ]\n }\n]", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users", "parameters": [ { @@ -420,7 +420,7 @@ "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/system/total", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nResponse 200: List\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nResponse 200: List\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/system/total", "headers": [], "authentication": { @@ -436,7 +436,7 @@ "parentId": "fld_wallet_admin", "name": "GET /opex/v1/admin/wallet/users/total", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nResponse 200: List | null\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nResponse 200: List | null\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users/total", "headers": [], "authentication": { @@ -458,7 +458,7 @@ "parentId": "fld_voucher", "name": "PUT /opex/v1/voucher/{code}", "method": "PUT", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Insomnia token: {{ _['user-token'] }}.\n- Config note: SecurityConfig defines PERM_voucher:submit for /opex/v1/voucher, but this request calls /opex/v1/voucher/{code}.\n- Effective matcher for this exact URL may fall back to anyExchange().authenticated() unless the matcher is changed to /opex/v1/voucher/**.\n- Intended authority to use for voucher-submit tokens: PERM_voucher:submit.\n\nPath params:\n- code: string\n\nResponse 200: SubmitVoucherResponse\n{\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"issuer\": \"string | null\",\n \"description\": \"string | null\"\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_voucher:submit.\n\nPath params:\n- code: string\n\nResponse 200: SubmitVoucherResponse\n{\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"issuer\": \"string | null\",\n \"description\": \"string | null\"\n}", "url": "{{ _['api-host'] }}/opex/v1/voucher/{{ _['code'] }}", "headers": [], "authentication": { @@ -480,7 +480,7 @@ "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/trade/volume", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nQuery params:\n- symbol: string, e.g. BTCUSDT\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nQuery params:\n- symbol: string, e.g. BTCUSDT\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume", "parameters": [ { @@ -508,7 +508,7 @@ "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/trade/volume/total", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nQuery params:\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nQuery params:\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume/total", "parameters": [ { @@ -531,7 +531,7 @@ "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/fee", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nResponse 200: UserFee\n{\n \"name\": \"string\",\n \"makerFee\": \"BigDecimal\",\n \"takerFee\": \"BigDecimal\"\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nResponse 200: UserFee\n{\n \"name\": \"string\",\n \"makerFee\": \"BigDecimal\",\n \"takerFee\": \"BigDecimal\"\n}", "url": "{{ _['api-host'] }}/opex/v1/user/data/fee", "headers": [], "authentication": { @@ -547,7 +547,7 @@ "parentId": "fld_user_data", "name": "GET /opex/v1/user/data/withdraw/volume/total", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: authenticated() only; no specific role/permission matcher is defined for /opex/v1/user/data/**.\n- Insomnia token: {{ _['user-token'] }}.\n- Effective matcher: anyExchange().authenticated().\n\nQuery params:\n- interval: string | null\n- Accepted labels map to Interval, commonly: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nQuery params:\n- interval: string | null\n- Accepted labels map to Interval, commonly: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", "url": "{{ _['api-host'] }}/opex/v1/user/data/withdraw/volume/total", "parameters": [ { @@ -576,7 +576,7 @@ "parentId": "fld_bank_account", "name": "POST /opex/v1/bank-account", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_bank_account:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_bank_account:write.\n - Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid.\n- Security matcher: /opex/v1/bank-account/**.\n\nRequest body: AddBankAccountRequest\n{\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\"\n}\n\nResponse 200: BankAccountResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n}", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nValidation:\n- Exactly one of `cardNumber` or `iban` must be provided.\n- Providing both or neither is invalid.\n\nRequest body: AddBankAccountRequest\n{\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\"\n}\n\nValid request with card number:\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": \"6037991234567890\",\n \"iban\": null\n}\n\nValid request with IBAN:\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": null,\n \"iban\": \"IR123456789012345678901234\"\n}\n\nInvalid request: both cardNumber and iban are provided.\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": \"6037991234567890\",\n \"iban\": \"IR123456789012345678901234\"\n}\n\nInvalid request: neither cardNumber nor iban is provided.\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": null,\n \"iban\": null\n}\n\nResponse 200: BankAccountResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n}\n\nResponse 401:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/bank-account", "body": { "mimeType": "application/json", @@ -601,7 +601,7 @@ "parentId": "fld_bank_account", "name": "GET /opex/v1/bank-account", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: none.\n- Required authority: permitAll for GET /opex/v1/bank-account.\n- Insomnia token: optional; the collection currently sends {{ _['user-token'] }}, but the endpoint is public according to SecurityConfig.\n- Security matcher: GET /opex/v1/bank-account.\n\nResponse 200: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n }\n]", + "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nResponse 200: Array\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n }\n]\n\nResponse 401:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/bank-account", "headers": [], "authentication": { @@ -617,7 +617,7 @@ "parentId": "fld_bank_account", "name": "DELETE /opex/v1/bank-account/{id}", "method": "DELETE", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: PERM_bank_account:write.\n- Insomnia token: {{ _['user-token'] }}; paste a user/API-key JWT that contains PERM_bank_account:write.\n- Security matcher: /opex/v1/bank-account/**.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_bank_account:write.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.\n\nResponse 401:\nNo response body.\n\nResponse 403:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/bank-account/{{ _['id'] }}", "headers": [], "authentication": { @@ -639,7 +639,7 @@ "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/currency/{currency}/localization", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- currency: string\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- currency: string\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", "headers": [], "authentication": { @@ -655,7 +655,7 @@ "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/currency/{currency}/localization", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- currency: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- currency: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", "body": { "mimeType": "application/json", @@ -680,7 +680,7 @@ "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/currency/localization/{id}", "method": "DELETE", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/admin/currency/localization/{{ _['id'] }}", "headers": [], "authentication": { @@ -696,7 +696,7 @@ "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/terminal/{terminalUuid}/localization", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- terminalUuid: string\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- terminalUuid: string\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", "headers": [], "authentication": { @@ -712,7 +712,7 @@ "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/terminal/{terminalUuid}/localization", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- terminalUuid: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- terminalUuid: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", "body": { "mimeType": "application/json", @@ -737,7 +737,7 @@ "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/terminal/localization/{id}", "method": "DELETE", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/localization/{{ _['id'] }}", "headers": [], "authentication": { @@ -753,7 +753,7 @@ "parentId": "fld_localization_admin", "name": "GET /opex/v1/admin/gateway/{gatewayUuid}/localization", "method": "GET", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" uses off-chain gateway localization.\n- gatewayUuid starting with \"ong\" uses on-chain gateway localization.\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" uses off-chain gateway localization.\n- gatewayUuid starting with \"ong\" uses on-chain gateway localization.\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", "headers": [], "authentication": { @@ -769,7 +769,7 @@ "parentId": "fld_localization_admin", "name": "POST /opex/v1/admin/gateway/{gatewayUuid}/localization", "method": "POST", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" saves off-chain gateway localization.\n- gatewayUuid starting with \"ong\" saves on-chain gateway localization.\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" saves off-chain gateway localization.\n- gatewayUuid starting with \"ong\" saves on-chain gateway localization.\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", "body": { "mimeType": "application/json", @@ -794,7 +794,7 @@ "parentId": "fld_localization_admin", "name": "DELETE /opex/v1/admin/gateway/{gatewayUuid}/localization/{id}", "method": "DELETE", - "description": "Security / Auth (from api-binance-rest SecurityConfig):\n- Required: Bearer JWT.\n- Required authority: ROLE_admin.\n- Insomnia token: {{ _['admin-token'] }}.\n- Security matcher: /opex/v1/admin/**.\n\nPath params:\n- gatewayUuid: string\n- id: Long\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" deletes off-chain gateway localization.\n- gatewayUuid starting with \"ong\" deletes on-chain gateway localization.\n\nResponse 200:\nNo response body.", + "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- gatewayUuid: string\n- id: Long\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" deletes off-chain gateway localization.\n- gatewayUuid starting with \"ong\" deletes on-chain gateway localization.\n\nResponse 200:\nNo response body.", "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization/{{ _['id'] }}", "headers": [], "authentication": { @@ -805,4 +805,4 @@ } } ] -} +} \ No newline at end of file diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt index 21783e070..a02dcb1f1 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt @@ -10,17 +10,28 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/address-book") -@Tag(name = "Address Book", description = "Manage user address book entries") +@Tag( + name = "Address Book", + description = "Manage authenticated user's address book entries." +) class AddressBookController( val profileProxy: ProfileProxy, ) { @@ -28,22 +39,85 @@ class AddressBookController( @PostMapping @Operation( summary = "Add address book entry", - description = "Creates a new address book entry for the authenticated user.", + description = """ +Creates a new address book entry for the authenticated user. + +Required authentication: +- Bearer JWT + +Request body: AddAddressBookItemRequest +- name: string, required +- address: string, required +- addressType: string, required + +Notes: +- addressType is a server-provided string value. +- Clients should use the exact value returned by the related chain/address-type source service. +- Do not treat addressType as a fixed enum and do not hardcode a static value list. + +Response body: AddressBookResponse +- id: Long, nullable +- name: string +- address: string +- addressType: string + """, security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, - content = [Content(mediaType = "application/json", schema = Schema(implementation = AddAddressBookItemRequest::class))] + description = "Address book entry creation payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = AddAddressBookItemRequest::class), + examples = [ + ExampleObject( + name = "Create address book entry", + value = """ +{ + "name": "Home Wallet", + "address": "0x1234567890abcdef1234567890abcdef12345678", + "addressType": "ethereum" +} + """ + ) + ] + ) + ] ), responses = [ ApiResponse( responseCode = "200", - description = "Created/Updated", - content = [Content(mediaType = "application/json", schema = Schema(implementation = AddressBookResponse::class))] + description = "Address book entry created successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = AddressBookResponse::class), + examples = [ + ExampleObject( + name = "Address book response", + value = """ +{ + "id": 1, + "name": "Home Wallet", + "address": "0x1234567890abcdef1234567890abcdef12345678", + "addressType": "ethereum" +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] ) ] ) suspend fun addAddressBook( @RequestBody request: AddAddressBookItemRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): AddressBookResponse { return profileProxy.addAddressBook(securityContext.jwtAuthentication().tokenValue(), request) @@ -52,34 +126,104 @@ class AddressBookController( @GetMapping @Operation( summary = "List address book entries", - description = "Returns all address book entries for the authenticated user.", + description = """ +Returns all address book entries for the authenticated user. + +Required authentication: +- Bearer JWT + +Response body: Array +Each item: +- id: Long, nullable +- name: string +- address: string +- addressType: string + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", - description = "OK", - content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = AddressBookResponse::class)))] + description = "Address book entries returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema( + schema = Schema(implementation = AddressBookResponse::class) + ), + examples = [ + ExampleObject( + name = "Address book list response", + value = """ +[ + { + "id": 1, + "name": "Home Wallet", + "address": "0x1234567890abcdef1234567890abcdef12345678", + "addressType": "ethereum" + } +] + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] ) ] ) - suspend fun getAddressBook(@CurrentSecurityContext securityContext: SecurityContext): List { + suspend fun getAddressBook( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ): List { return profileProxy.getAllAddressBooks(securityContext.jwtAuthentication().tokenValue()) } @DeleteMapping("/{id}") @Operation( summary = "Delete address book entry", - description = "Deletes an address book entry by id.", + description = """ +Deletes one address book entry by ID for the authenticated user. + +Required authentication: +- Bearer JWT + +Path parameters: +- id: Address book entry ID. + +Response body: +- No response body. + """, security = [SecurityRequirement(name = "bearerAuth")], parameters = [ - Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) + Parameter( + name = "id", + `in` = ParameterIn.PATH, + required = true, + description = "Address book entry ID.", + schema = Schema(type = "integer", format = "int64"), + example = "1" + ) ], responses = [ - ApiResponse(responseCode = "200", description = "Deleted") + ApiResponse( + responseCode = "200", + description = "Address book entry deleted successfully. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) suspend fun deleteAddressBook( @PathVariable("id") id: Long, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ) { profileProxy.deleteAddressBook(securityContext.jwtAuthentication().tokenValue(), id) @@ -88,29 +232,101 @@ class AddressBookController( @PutMapping("/{id}") @Operation( summary = "Update address book entry", - description = "Updates an existing address book entry by id.", + description = """ +Updates one address book entry by ID for the authenticated user. + +Required authentication: +- Bearer JWT + +Path parameters: +- id: Address book entry ID. + +Request body: AddAddressBookItemRequest +- name: string, required +- address: string, required +- addressType: string, required + +Notes: +- addressType is a server-provided string value. +- Clients should use the exact value returned by the related chain/address-type source service. +- Do not treat addressType as a fixed enum and do not hardcode a static value list. + +Response body: AddressBookResponse +- id: Long, nullable +- name: string +- address: string +- addressType: string + """, security = [SecurityRequirement(name = "bearerAuth")], parameters = [ - Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) + Parameter( + name = "id", + `in` = ParameterIn.PATH, + required = true, + description = "Address book entry ID.", + schema = Schema(type = "integer", format = "int64"), + example = "1" + ) ], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, - content = [Content(mediaType = "application/json", schema = Schema(implementation = AddAddressBookItemRequest::class))] + description = "Address book entry update payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = AddAddressBookItemRequest::class), + examples = [ + ExampleObject( + name = "Update address book entry", + value = """ +{ + "name": "Updated Wallet Name", + "address": "0x1234567890abcdef1234567890abcdef12345678", + "addressType": "ethereum" +} + """ + ) + ] + ) + ] ), responses = [ ApiResponse( responseCode = "200", - description = "OK", - content = [Content(mediaType = "application/json", schema = Schema(implementation = AddressBookResponse::class))] + description = "Address book entry updated successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = AddressBookResponse::class), + examples = [ + ExampleObject( + name = "Address book response", + value = """ +{ + "id": 1, + "name": "Updated Wallet Name", + "address": "0x1234567890abcdef1234567890abcdef12345678", + "addressType": "ethereum" +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] ) ] ) suspend fun updateAddressBook( @PathVariable("id") id: Long, @RequestBody request: AddAddressBookItemRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): AddressBookResponse { return profileProxy.updateAddressBook(securityContext.jwtAuthentication().tokenValue(), id, request) } - -} \ No newline at end of file +} diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt index 981ff3c59..08c07f63e 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/ProfileProxyImpl.kt @@ -131,7 +131,7 @@ class ProfileProxyImpl(@Qualifier("generalWebClient") private val webClient: Web override suspend fun getAllAddressBooks(token: String): List { return webClient.get() - .uri("$baseUrl/address-book`") + .uri("$baseUrl/address-book") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() From e6d7d2d0ad3325829db4ffdbc0e2c05529e7c6a6 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 11 May 2026 22:04:22 +0330 Subject: [PATCH 08/56] Complete insomnia/swagger data about otc-rate services --- .../controller/CurrencyRatesController.kt | 1015 ++++++++++++++++- 1 file changed, 1011 insertions(+), 4 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt index 717bfdd61..5a417386d 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt @@ -4,19 +4,94 @@ import co.nilin.opex.api.core.inout.otc.* import co.nilin.opex.api.core.spi.RateProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController -@RequestMapping( "/opex/v1/otc") +@RequestMapping("/opex/v1/otc") class CurrencyRatesController( private val rateProxy: RateProxy ) { // Rates @PostMapping("/rate") + @Operation( + tags = ["OTC Rates"], + summary = "Create OTC exchange rate", + description = """ +Creates a new OTC exchange rate. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Validation: +- `rate` must be greater than zero. +- `sourceSymbol` and `destSymbol` must be different. + +Request body: SetCurrencyExchangeRateRequest +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- ignoreIfExist: boolean, nullable, default false + +Response body: +- No response body. + """, + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "OTC exchange rate creation payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), + examples = [ + ExampleObject( + name = "Create OTC rate request", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00, + "ignoreIfExist": false +} + """ + ) + ] + ) + ] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "OTC exchange rate created successfully. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun createRate( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody request: SetCurrencyExchangeRateRequest ) { @@ -25,7 +100,99 @@ class CurrencyRatesController( } @PutMapping("/rate") + @Operation( + tags = ["OTC Rates"], + summary = "Update OTC exchange rate", + description = """ +Updates an existing OTC exchange rate. + +Required authentication: +- Bearer admin-token or service token is required. +- Required role: ROLE_admin or ROLE_rate_bot. + +Validation: +- `rate` must be greater than zero. +- `sourceSymbol` and `destSymbol` must be different. + +Request body: SetCurrencyExchangeRateRequest +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- ignoreIfExist: boolean, nullable, default false + +Response body: Rates +- rates: Array, nullable + +Rate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "OTC exchange rate update payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), + examples = [ + ExampleObject( + name = "Update OTC rate request", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65100.00, + "ignoreIfExist": false +} + """ + ) + ] + ) + ] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "OTC exchange rate updated successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rates::class), + examples = [ + ExampleObject( + name = "Rates response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65100.00 + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin or ROLE_rate_bot. No response body.", + content = [Content()] + ) + ] + ) suspend fun updateRate( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody request: SetCurrencyExchangeRateRequest ): Rates { @@ -34,7 +201,88 @@ class CurrencyRatesController( } @DeleteMapping("/rate/{sourceSymbol}/{destSymbol}") + @Operation( + tags = ["OTC Rates"], + summary = "Delete OTC exchange rate", + description = """ +Deletes an OTC exchange rate by source and destination symbols. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Path parameters: +- sourceSymbol: source currency symbol. +- destSymbol: destination currency symbol. + +Response body: Rates +- rates: Array, nullable + +Rate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Source currency symbol.", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Destination currency symbol.", + example = "USDT", + schema = Schema(type = "string") + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "OTC exchange rate deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rates::class), + examples = [ + ExampleObject( + name = "Rates response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "ETH", + "destSymbol": "USDT", + "rate": 3200.00 + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun deleteRate( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable sourceSymbol: String, @PathVariable destSymbol: String @@ -43,11 +291,118 @@ class CurrencyRatesController( } @GetMapping("/rate") + @Operation( + tags = ["OTC Rates"], + summary = "List OTC exchange rates", + description = """ +Returns configured OTC exchange rates. + +Authentication: +- Public endpoint. No Bearer token is required. + +Response body: Rates +- rates: Array, nullable + +Rate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, + responses = [ + ApiResponse( + responseCode = "200", + description = "OTC exchange rates returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rates::class), + examples = [ + ExampleObject( + name = "Rates response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00 + } + ] +} + """ + ) + ] + ) + ] + ) + ] + ) suspend fun fetchRates(): Rates { return rateProxy.fetchRates() } @GetMapping("/rate/{sourceSymbol}/{destSymbol}") + @Operation( + tags = ["OTC Rates"], + summary = "Get OTC exchange rate", + description = """ +Returns one OTC exchange rate by source and destination symbols. + +Authentication: +- Public endpoint. No Bearer token is required. + +Path parameters: +- sourceSymbol: source currency symbol. +- destSymbol: destination currency symbol. + +Response body: Rate, nullable +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Source currency symbol.", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Destination currency symbol.", + example = "USDT", + schema = Schema(type = "string") + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "OTC exchange rate returned successfully. Response may be null if no rate exists.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rate::class), + examples = [ + ExampleObject( + name = "Rate response", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00 +} + """ + ) + ] + ) + ] + ) + ] + ) suspend fun fetchRate( @PathVariable sourceSymbol: String, @PathVariable destSymbol: String @@ -57,7 +412,68 @@ class CurrencyRatesController( // Forbidden pairs @PostMapping("/forbidden-pairs") + @Operation( + tags = ["OTC Forbidden Pairs"], + summary = "Add forbidden OTC pair", + description = """ +Adds a forbidden OTC currency pair. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Validation: +- `sourceSymbol` and `destSymbol` must be different. + +Request body: CurrencyPair +- sourceSymbol: string +- destSymbol: string + +Response body: +- No response body. + """, + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "Forbidden OTC pair payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = CurrencyPair::class), + examples = [ + ExampleObject( + name = "Forbidden pair request", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "IRR" +} + """ + ) + ] + ) + ] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Forbidden pair added successfully. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun addForbiddenPair( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody request: CurrencyPair ) { @@ -66,7 +482,86 @@ class CurrencyRatesController( } @DeleteMapping("/forbidden-pairs/{sourceSymbol}/{destSymbol}") + @Operation( + tags = ["OTC Forbidden Pairs"], + summary = "Delete forbidden OTC pair", + description = """ +Deletes one forbidden OTC currency pair. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Path parameters: +- sourceSymbol: source currency symbol. +- destSymbol: destination currency symbol. + +Response body: ForbiddenPairs +- forbiddenPairs: Array, nullable + +ForbiddenPair item: +- sourceSymbol: string +- destinationSymbol: string + """, + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Source currency symbol.", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Destination currency symbol.", + example = "IRR", + schema = Schema(type = "string") + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "Forbidden pair deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = ForbiddenPairs::class), + examples = [ + ExampleObject( + name = "Forbidden pairs response", + value = """ +{ + "forbiddenPairs": [ + { + "sourceSymbol": "ETH", + "destinationSymbol": "IRR" + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun deleteForbiddenPair( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable sourceSymbol: String, @PathVariable destSymbol: String @@ -75,13 +570,116 @@ class CurrencyRatesController( } @GetMapping("/forbidden-pairs") + @Operation( + tags = ["OTC Forbidden Pairs"], + summary = "List forbidden OTC pairs", + description = """ +Returns forbidden OTC currency pairs. + +Authentication: +- Public endpoint. No Bearer token is required. + +Response body: ForbiddenPairs +- forbiddenPairs: Array, nullable + +ForbiddenPair item: +- sourceSymbol: string +- destinationSymbol: string + """, + responses = [ + ApiResponse( + responseCode = "200", + description = "Forbidden OTC pairs returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = ForbiddenPairs::class), + examples = [ + ExampleObject( + name = "Forbidden pairs response", + value = """ +{ + "forbiddenPairs": [ + { + "sourceSymbol": "BTC", + "destinationSymbol": "IRR" + } + ] +} + """ + ) + ] + ) + ] + ) + ] + ) suspend fun fetchForbiddenPairs(): ForbiddenPairs { return rateProxy.fetchForbiddenPairs() } // Transitive symbols @PostMapping("/transitive-symbols") + @Operation( + tags = ["OTC Transitive Symbols"], + summary = "Add transitive OTC symbols", + description = """ +Adds transitive symbols used for OTC route calculation. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Request body: Symbols +- symbols: Array, nullable + +Response body: +- No response body. + """, + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "Transitive symbols payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Transitive symbols request", + value = """ +{ + "symbols": [ + "USDT", + "IRR" + ] +} + """ + ) + ] + ) + ] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Transitive symbols added successfully. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun addTransitiveSymbols( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody symbols: Symbols ) { @@ -89,7 +687,70 @@ class CurrencyRatesController( } @DeleteMapping("/transitive-symbols/{symbol}") + @Operation( + tags = ["OTC Transitive Symbols"], + summary = "Delete one transitive OTC symbol", + description = """ +Deletes one transitive symbol used for OTC route calculation. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Path parameters: +- symbol: symbol to delete. + +Response body: Symbols +- symbols: Array, nullable + """, + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "symbol", + `in` = ParameterIn.PATH, + required = true, + description = "Transitive symbol to delete.", + example = "USDT", + schema = Schema(type = "string") + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "Transitive symbol deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Symbols response", + value = """ +{ + "symbols": [ + "IRR" + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun deleteTransitiveSymbols( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable symbol: String ): Symbols { @@ -97,7 +758,83 @@ class CurrencyRatesController( } @DeleteMapping("/transitive-symbols") + @Operation( + tags = ["OTC Transitive Symbols"], + summary = "Delete multiple transitive OTC symbols", + description = """ +Deletes multiple transitive symbols used for OTC route calculation. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Request body: Symbols +- symbols: Array, nullable + +Response body: Symbols +- symbols: Array, nullable + """, + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "Transitive symbols delete payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Delete transitive symbols request", + value = """ +{ + "symbols": [ + "USDT", + "IRR" + ] +} + """ + ) + ] + ) + ] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Transitive symbols deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Symbols response", + value = """ +{ + "symbols": [ + "USDT" + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun deleteTransitiveSymbols( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody symbols: Symbols ): Symbols { @@ -105,20 +842,290 @@ class CurrencyRatesController( } @GetMapping("/transitive-symbols") + @Operation( + tags = ["OTC Transitive Symbols"], + summary = "List transitive OTC symbols", + description = """ +Returns transitive symbols used for OTC route calculation. + +Authentication: +- Public endpoint. No Bearer token is required. + +Response body: Symbols +- symbols: Array, nullable + """, + responses = [ + ApiResponse( + responseCode = "200", + description = "Transitive symbols returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Symbols response", + value = """ +{ + "symbols": [ + "USDT", + "IRR" + ] +} + """ + ) + ] + ) + ] + ) + ] + ) suspend fun fetchTransitiveSymbols(): Symbols { return rateProxy.fetchTransitiveSymbols() } // Routes and prices - @RequestMapping("/route", method = [RequestMethod.POST, RequestMethod.GET]) + @GetMapping("/route") + @Operation( + tags = ["OTC Routes & Prices"], + summary = "Calculate OTC exchange routes", + description = """ +Returns calculated OTC exchange routes. + +Authentication: +- Public endpoint. No Bearer token is required. + +Query parameters: +- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. +- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. + +Route calculation behavior: +- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. +- If sourceSymbol is omitted, routes are calculated from all possible source symbols. +- If destSymbol is omitted, routes are calculated to all possible destination symbols. +- If both are omitted, routes are calculated for all possible symbol combinations. +- Do not send the literal string "null". Omit the query parameter when it should be treated as null. + +Response body: CurrencyExchangeRatesResponse +- rates: Array + +CurrencyExchangeRate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- isSwappable: boolean + """, + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional source currency symbol. If omitted, all possible source symbols are considered. Do not send the literal string \"null\".", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Do not send the literal string \"null\".", + example = "USDT", + schema = Schema(type = "string") + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "OTC exchange routes returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = CurrencyExchangeRatesResponse::class), + examples = [ + ExampleObject( + name = "Currency exchange routes response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00, + "isSwappable": true + } + ] +} + """ + ) + ] + ) + ] + ) + ] + ) suspend fun fetchRoutes( - @RequestParam("sourceSymbol") sourceSymbol: String? = null, - @RequestParam("destSymbol") destSymbol: String? = null + @RequestParam("sourceSymbol", required = false) sourceSymbol: String? = null, + @RequestParam("destSymbol", required = false) destSymbol: String? = null + ): CurrencyExchangeRatesResponse { + return rateProxy.fetchRoutes(sourceSymbol, destSymbol) + } + + @PostMapping("/route") + @Operation( + tags = ["OTC Routes & Prices"], + summary = "Calculate OTC exchange routes as admin", + description = """ +Returns calculated OTC exchange routes. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Query parameters: +- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. +- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. + +Route calculation behavior: +- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. +- If sourceSymbol is omitted, routes are calculated from all possible source symbols. +- If destSymbol is omitted, routes are calculated to all possible destination symbols. +- If both are omitted, routes are calculated for all possible symbol combinations. +- Do not send the literal string "null". Omit the query parameter when it should be treated as null. + +Request body: +- No request body. + +Response body: CurrencyExchangeRatesResponse +- rates: Array + +CurrencyExchangeRate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- isSwappable: boolean + """, + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional source currency symbol. If omitted, all possible source symbols are considered. Do not send the literal string \"null\".", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Do not send the literal string \"null\".", + example = "USDT", + schema = Schema(type = "string") + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "OTC exchange routes returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = CurrencyExchangeRatesResponse::class), + examples = [ + ExampleObject( + name = "Currency exchange routes response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00, + "isSwappable": true + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) + suspend fun fetchRoutesAsAdmin( + @RequestParam("sourceSymbol", required = false) sourceSymbol: String? = null, + @RequestParam("destSymbol", required = false) destSymbol: String? = null ): CurrencyExchangeRatesResponse { return rateProxy.fetchRoutes(sourceSymbol, destSymbol) } @GetMapping("/currency/price") + @Operation( + tags = ["OTC Routes & Prices"], + summary = "Get OTC currency prices", + description = """ +Returns OTC currency prices for the requested unit. + +Authentication: +- Public endpoint. No Bearer token is required. + +Query parameters: +- unit: pricing unit. + +Response body: Array +Each item: +- currency: string +- buyPrice: BigDecimal, nullable +- sellPrice: BigDecimal, nullable + """, + parameters = [ + Parameter( + name = "unit", + `in` = ParameterIn.QUERY, + required = true, + description = "Pricing unit.", + example = "USDT", + schema = Schema(type = "string") + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "Currency prices returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = CurrencyPrice::class)), + examples = [ + ExampleObject( + name = "Currency price list response", + value = """ +[ + { + "currency": "BTC", + "buyPrice": 65000.00, + "sellPrice": 65100.00 + } +] + """ + ) + ] + ) + ] + ) + ] + ) suspend fun getPrice( @RequestParam("unit") unit: String ): List { From 5206b7dc775fe714c19ace73465ee91175814e78 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 11 May 2026 22:05:27 +0330 Subject: [PATCH 09/56] Update insomnia data about otc-rate services --- Insomnia_2026-05-10.json | 292 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 291 insertions(+), 1 deletion(-) diff --git a/Insomnia_2026-05-10.json b/Insomnia_2026-05-10.json index 05ebd03ec..a83475896 100644 --- a/Insomnia_2026-05-10.json +++ b/Insomnia_2026-05-10.json @@ -37,7 +37,11 @@ "symbol": "BTCUSDT", "interval": "Month", "bucket": "public", - "key": "logo.png" + "key": "logo.png", + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "unit": "USDT", + "transitiveSymbol": "USDT" } }, { @@ -803,6 +807,292 @@ "token": "{{_['admin-token']}}", "prefix": "" } + }, + { + "_id": "fld_otc_rates", + "_type": "request_group", + "parentId": "fld_api_opex_rest", + "name": "OTC / Rates" + }, + { + "_id": "req_otc_rate_post", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "POST /opex/v1/otc/rate", + "method": "POST", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nValidation:\n- `rate` must be greater than zero.\n- `sourceSymbol` and `destSymbol` must be different.\n\nRequest body: SetCurrencyExchangeRateRequest\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"ignoreIfExist\": \"boolean | null\"\n}\n\nResponse 200:\nNo response body.\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/rate", + "body": { + "mimeType": "application/json", + "text": "{\n \"sourceSymbol\": \"BTC\",\n \"destSymbol\": \"USDT\",\n \"rate\": 65000.00,\n \"ignoreIfExist\": false\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_rate_put", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "PUT /opex/v1/otc/rate", + "method": "PUT", + "description": "Auth:\n- Bearer admin-token or service token is required.\n- Required role: ROLE_admin or ROLE_rate_bot.\n\nValidation:\n- `rate` must be greater than zero.\n- `sourceSymbol` and `destSymbol` must be different.\n\nRequest body: SetCurrencyExchangeRateRequest\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"ignoreIfExist\": \"boolean | null\"\n}\n\nResponse 200: Rates\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/rate", + "body": { + "mimeType": "application/json", + "text": "{\n \"sourceSymbol\": \"BTC\",\n \"destSymbol\": \"USDT\",\n \"rate\": 65100.00,\n \"ignoreIfExist\": false\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_rate_delete", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "DELETE /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}", + "method": "DELETE", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nPath params:\n- sourceSymbol: string\n- destSymbol: string\n\nResponse 200: Rates\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/rate/{{ _['sourceSymbol'] }}/{{ _['destSymbol'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_rates_get", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "GET /opex/v1/otc/rate", + "method": "GET", + "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nResponse 200: Rates\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/otc/rate", + "headers": [] + }, + { + "_id": "req_otc_rate_get", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "GET /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}", + "method": "GET", + "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nPath params:\n- sourceSymbol: string\n- destSymbol: string\n\nResponse 200: Rate, nullable\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n}", + "url": "{{ _['api-host'] }}/opex/v1/otc/rate/{{ _['sourceSymbol'] }}/{{ _['destSymbol'] }}", + "headers": [] + }, + { + "_id": "req_otc_forbidden_post", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "POST /opex/v1/otc/forbidden-pairs", + "method": "POST", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nValidation:\n- `sourceSymbol` and `destSymbol` must be different.\n\nRequest body: CurrencyPair\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\"\n}\n\nResponse 200:\nNo response body.\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/forbidden-pairs", + "body": { + "mimeType": "application/json", + "text": "{\n \"sourceSymbol\": \"BTC\",\n \"destSymbol\": \"IRR\"\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_forbidden_delete", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "DELETE /opex/v1/otc/forbidden-pairs/{sourceSymbol}/{destSymbol}", + "method": "DELETE", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nPath params:\n- sourceSymbol: string\n- destSymbol: string\n\nResponse 200: ForbiddenPairs\n{\n \"forbiddenPairs\": [\n {\n \"sourceSymbol\": \"string\",\n \"destinationSymbol\": \"string\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/forbidden-pairs/{{ _['sourceSymbol'] }}/{{ _['destSymbol'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_forbidden_get", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "GET /opex/v1/otc/forbidden-pairs", + "method": "GET", + "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nResponse 200: ForbiddenPairs\n{\n \"forbiddenPairs\": [\n {\n \"sourceSymbol\": \"string\",\n \"destinationSymbol\": \"string\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/otc/forbidden-pairs", + "headers": [] + }, + { + "_id": "req_otc_transitive_post", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "POST /opex/v1/otc/transitive-symbols", + "method": "POST", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nRequest body: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 200:\nNo response body.\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols", + "body": { + "mimeType": "application/json", + "text": "{\n \"symbols\": [\n \"USDT\",\n \"IRR\"\n ]\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_transitive_delete_one", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "DELETE /opex/v1/otc/transitive-symbols/{symbol}", + "method": "DELETE", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nPath params:\n- symbol: string\n\nResponse 200: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols/{{ _['transitiveSymbol'] }}", + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_transitive_delete_bulk", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "DELETE /opex/v1/otc/transitive-symbols", + "method": "DELETE", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nRequest body: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 200: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols", + "body": { + "mimeType": "application/json", + "text": "{\n \"symbols\": [\n \"USDT\",\n \"IRR\"\n ]\n}" + }, + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_transitive_get", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "GET /opex/v1/otc/transitive-symbols", + "method": "GET", + "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nResponse 200: Symbols\n{\n \"symbols\": [\"string\"]\n}", + "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols", + "headers": [] + }, + { + "_id": "req_otc_route_get", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "GET /opex/v1/otc/route", + "method": "GET", + "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nQuery params:\n- sourceSymbol: string, optional. If omitted, all possible source symbols are considered.\n- destSymbol: string, optional. If omitted, all possible destination symbols are considered.\n\nRoute calculation behavior:\n- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair.\n- If sourceSymbol is omitted, routes are calculated from all possible source symbols.\n- If destSymbol is omitted, routes are calculated to all possible destination symbols.\n- If both are omitted, routes are calculated for all possible symbol combinations.\n- Do not send the literal string \"null\". Remove/disable the query parameter when it should be treated as null.\n\nUsage examples:\n- Specific pair: keep both sourceSymbol and destSymbol.\n- All destinations from one source: keep sourceSymbol and remove/disable destSymbol.\n- All sources to one destination: keep destSymbol and remove/disable sourceSymbol.\n- All possible combinations: remove/disable both sourceSymbol and destSymbol.\n\nResponse 200: CurrencyExchangeRatesResponse\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"isSwappable\": \"boolean\"\n }\n ]\n}", + "url": "{{ _['api-host'] }}/opex/v1/otc/route", + "parameters": [ + { + "name": "sourceSymbol", + "value": "{{ _['sourceSymbol'] }}", + "description": "Optional source currency symbol. If omitted, all possible source symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." + }, + { + "name": "destSymbol", + "value": "{{ _['destSymbol'] }}", + "description": "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." + } + ], + "headers": [] + }, + { + "_id": "req_otc_route_post", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "POST /opex/v1/otc/route", + "method": "POST", + "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nQuery params:\n- sourceSymbol: string, optional. If omitted, all possible source symbols are considered.\n- destSymbol: string, optional. If omitted, all possible destination symbols are considered.\n\nRoute calculation behavior:\n- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair.\n- If sourceSymbol is omitted, routes are calculated from all possible source symbols.\n- If destSymbol is omitted, routes are calculated to all possible destination symbols.\n- If both are omitted, routes are calculated for all possible symbol combinations.\n- Do not send the literal string \"null\". Remove/disable the query parameter when it should be treated as null.\n\nUsage examples:\n- Specific pair: keep both sourceSymbol and destSymbol.\n- All destinations from one source: keep sourceSymbol and remove/disable destSymbol.\n- All sources to one destination: keep destSymbol and remove/disable sourceSymbol.\n- All possible combinations: remove/disable both sourceSymbol and destSymbol.\n\nRequest body:\nNo request body.\n\nResponse 200: CurrencyExchangeRatesResponse\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"isSwappable\": \"boolean\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", + "url": "{{ _['api-host'] }}/opex/v1/otc/route", + "parameters": [ + { + "name": "sourceSymbol", + "value": "{{ _['sourceSymbol'] }}", + "description": "Optional source currency symbol. If omitted, all possible source symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." + }, + { + "name": "destSymbol", + "value": "{{ _['destSymbol'] }}", + "description": "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." + } + ], + "headers": [], + "authentication": { + "type": "bearer", + "disabled": false, + "token": "{{_['admin-token']}}", + "prefix": "" + } + }, + { + "_id": "req_otc_currency_price_get", + "_type": "request", + "parentId": "fld_otc_rates", + "name": "GET /opex/v1/otc/currency/price", + "method": "GET", + "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nQuery params:\n- unit: string, required\n\nResponse 200: Array\n[\n {\n \"currency\": \"string\",\n \"buyPrice\": \"BigDecimal | null\",\n \"sellPrice\": \"BigDecimal | null\"\n }\n]", + "url": "{{ _['api-host'] }}/opex/v1/otc/currency/price", + "parameters": [ + { + "name": "unit", + "value": "{{ _['unit'] }}", + "description": "Pricing unit" + } + ], + "headers": [] } ] } \ No newline at end of file From 8fe5d2bf3cf899f77a14c4786ef33f127350a47f Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 12:07:47 +0330 Subject: [PATCH 10/56] Update swagger data about otc-rate services --- .../controller/CurrencyRatesController.kt | 997 ++---------------- 1 file changed, 94 insertions(+), 903 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt index 5a417386d..47c537672 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt @@ -4,21 +4,21 @@ import co.nilin.opex.api.core.inout.otc.* import co.nilin.opex.api.core.spi.RateProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/otc") +@Tag(name = "OTC / Currency Rates", description = "Manage OTC currency exchange rates, forbidden pairs, transitive symbols, routes, and currency prices.") class CurrencyRatesController( private val rateProxy: RateProxy ) { @@ -26,68 +26,16 @@ class CurrencyRatesController( // Rates @PostMapping("/rate") @Operation( - tags = ["OTC Rates"], - summary = "Create OTC exchange rate", + summary = "Create rate", description = """ -Creates a new OTC exchange rate. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Validation: -- `rate` must be greater than zero. -- `sourceSymbol` and `destSymbol` must be different. - -Request body: SetCurrencyExchangeRateRequest -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- ignoreIfExist: boolean, nullable, default false - -Response body: -- No response body. - """, + POST /opex/v1/otc/rate. + Bearer admin-token required. Required authority: ROLE_admin. + """, security = [SecurityRequirement(name = "bearerAuth")], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - description = "OTC exchange rate creation payload.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), - examples = [ - ExampleObject( - name = "Create OTC rate request", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00, - "ignoreIfExist": false -} - """ - ) - ] - ) - ] - ), responses = [ - ApiResponse( - responseCode = "200", - description = "OTC exchange rate created successfully. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun createRate( @@ -101,94 +49,16 @@ Response body: @PutMapping("/rate") @Operation( - tags = ["OTC Rates"], - summary = "Update OTC exchange rate", + summary = "Update rate", description = """ -Updates an existing OTC exchange rate. - -Required authentication: -- Bearer admin-token or service token is required. -- Required role: ROLE_admin or ROLE_rate_bot. - -Validation: -- `rate` must be greater than zero. -- `sourceSymbol` and `destSymbol` must be different. - -Request body: SetCurrencyExchangeRateRequest -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- ignoreIfExist: boolean, nullable, default false - -Response body: Rates -- rates: Array, nullable - -Rate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, + PUT /opex/v1/otc/rate. + Bearer admin-token required. Required authority: ROLE_admin or ROLE_rate_bot. + """, security = [SecurityRequirement(name = "bearerAuth")], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - description = "OTC exchange rate update payload.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), - examples = [ - ExampleObject( - name = "Update OTC rate request", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65100.00, - "ignoreIfExist": false -} - """ - ) - ] - ) - ] - ), responses = [ - ApiResponse( - responseCode = "200", - description = "OTC exchange rate updated successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Rates::class), - examples = [ - ExampleObject( - name = "Rates response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65100.00 - } - ] -} - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin or ROLE_rate_bot. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rates::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin or ROLE_rate_bot. No response body.", content = [Content()]) ] ) suspend fun updateRate( @@ -202,83 +72,16 @@ Rate item: @DeleteMapping("/rate/{sourceSymbol}/{destSymbol}") @Operation( - tags = ["OTC Rates"], - summary = "Delete OTC exchange rate", + summary = "Delete rate", description = """ -Deletes an OTC exchange rate by source and destination symbols. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Path parameters: -- sourceSymbol: source currency symbol. -- destSymbol: destination currency symbol. - -Response body: Rates -- rates: Array, nullable - -Rate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, + DELETE /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}. + Bearer admin-token required. Required authority: ROLE_admin. + """, security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter( - name = "sourceSymbol", - `in` = ParameterIn.PATH, - required = true, - description = "Source currency symbol.", - example = "BTC", - schema = Schema(type = "string") - ), - Parameter( - name = "destSymbol", - `in` = ParameterIn.PATH, - required = true, - description = "Destination currency symbol.", - example = "USDT", - schema = Schema(type = "string") - ) - ], responses = [ - ApiResponse( - responseCode = "200", - description = "OTC exchange rate deleted successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Rates::class), - examples = [ - ExampleObject( - name = "Rates response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "ETH", - "destSymbol": "USDT", - "rate": 3200.00 - } - ] -} - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rates::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun deleteRate( @@ -292,49 +95,12 @@ Rate item: @GetMapping("/rate") @Operation( - tags = ["OTC Rates"], - summary = "List OTC exchange rates", + summary = "Fetch rates", description = """ -Returns configured OTC exchange rates. - -Authentication: -- Public endpoint. No Bearer token is required. - -Response body: Rates -- rates: Array, nullable - -Rate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, + GET /opex/v1/otc/rate. + """, responses = [ - ApiResponse( - responseCode = "200", - description = "OTC exchange rates returned successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Rates::class), - examples = [ - ExampleObject( - name = "Rates response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00 - } - ] -} - """ - ) - ] - ) - ] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rates::class))]) ] ) suspend fun fetchRates(): Rates { @@ -343,64 +109,12 @@ Rate item: @GetMapping("/rate/{sourceSymbol}/{destSymbol}") @Operation( - tags = ["OTC Rates"], - summary = "Get OTC exchange rate", + summary = "Fetch rate", description = """ -Returns one OTC exchange rate by source and destination symbols. - -Authentication: -- Public endpoint. No Bearer token is required. - -Path parameters: -- sourceSymbol: source currency symbol. -- destSymbol: destination currency symbol. - -Response body: Rate, nullable -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, - parameters = [ - Parameter( - name = "sourceSymbol", - `in` = ParameterIn.PATH, - required = true, - description = "Source currency symbol.", - example = "BTC", - schema = Schema(type = "string") - ), - Parameter( - name = "destSymbol", - `in` = ParameterIn.PATH, - required = true, - description = "Destination currency symbol.", - example = "USDT", - schema = Schema(type = "string") - ) - ], + GET /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}. + """, responses = [ - ApiResponse( - responseCode = "200", - description = "OTC exchange rate returned successfully. Response may be null if no rate exists.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Rate::class), - examples = [ - ExampleObject( - name = "Rate response", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00 -} - """ - ) - ] - ) - ] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rate::class))]) ] ) suspend fun fetchRate( @@ -413,63 +127,16 @@ Response body: Rate, nullable // Forbidden pairs @PostMapping("/forbidden-pairs") @Operation( - tags = ["OTC Forbidden Pairs"], - summary = "Add forbidden OTC pair", + summary = "Add forbidden pair", description = """ -Adds a forbidden OTC currency pair. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Validation: -- `sourceSymbol` and `destSymbol` must be different. - -Request body: CurrencyPair -- sourceSymbol: string -- destSymbol: string - -Response body: -- No response body. - """, + POST /opex/v1/otc/forbidden-pairs. + Bearer admin-token required. Required authority: ROLE_admin. + """, security = [SecurityRequirement(name = "bearerAuth")], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - description = "Forbidden OTC pair payload.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = CurrencyPair::class), - examples = [ - ExampleObject( - name = "Forbidden pair request", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "IRR" -} - """ - ) - ] - ) - ] - ), responses = [ - ApiResponse( - responseCode = "200", - description = "Forbidden pair added successfully. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun addForbiddenPair( @@ -483,81 +150,16 @@ Response body: @DeleteMapping("/forbidden-pairs/{sourceSymbol}/{destSymbol}") @Operation( - tags = ["OTC Forbidden Pairs"], - summary = "Delete forbidden OTC pair", + summary = "Delete forbidden pair", description = """ -Deletes one forbidden OTC currency pair. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Path parameters: -- sourceSymbol: source currency symbol. -- destSymbol: destination currency symbol. - -Response body: ForbiddenPairs -- forbiddenPairs: Array, nullable - -ForbiddenPair item: -- sourceSymbol: string -- destinationSymbol: string - """, + DELETE /opex/v1/otc/forbidden-pairs/{sourceSymbol}/{destSymbol}. + Bearer admin-token required. Required authority: ROLE_admin. + """, security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter( - name = "sourceSymbol", - `in` = ParameterIn.PATH, - required = true, - description = "Source currency symbol.", - example = "BTC", - schema = Schema(type = "string") - ), - Parameter( - name = "destSymbol", - `in` = ParameterIn.PATH, - required = true, - description = "Destination currency symbol.", - example = "IRR", - schema = Schema(type = "string") - ) - ], responses = [ - ApiResponse( - responseCode = "200", - description = "Forbidden pair deleted successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = ForbiddenPairs::class), - examples = [ - ExampleObject( - name = "Forbidden pairs response", - value = """ -{ - "forbiddenPairs": [ - { - "sourceSymbol": "ETH", - "destinationSymbol": "IRR" - } - ] -} - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ForbiddenPairs::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun deleteForbiddenPair( @@ -571,47 +173,12 @@ ForbiddenPair item: @GetMapping("/forbidden-pairs") @Operation( - tags = ["OTC Forbidden Pairs"], - summary = "List forbidden OTC pairs", + summary = "Fetch forbidden pairs", description = """ -Returns forbidden OTC currency pairs. - -Authentication: -- Public endpoint. No Bearer token is required. - -Response body: ForbiddenPairs -- forbiddenPairs: Array, nullable - -ForbiddenPair item: -- sourceSymbol: string -- destinationSymbol: string - """, + GET /opex/v1/otc/forbidden-pairs. + """, responses = [ - ApiResponse( - responseCode = "200", - description = "Forbidden OTC pairs returned successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = ForbiddenPairs::class), - examples = [ - ExampleObject( - name = "Forbidden pairs response", - value = """ -{ - "forbiddenPairs": [ - { - "sourceSymbol": "BTC", - "destinationSymbol": "IRR" - } - ] -} - """ - ) - ] - ) - ] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ForbiddenPairs::class))]) ] ) suspend fun fetchForbiddenPairs(): ForbiddenPairs { @@ -621,61 +188,16 @@ ForbiddenPair item: // Transitive symbols @PostMapping("/transitive-symbols") @Operation( - tags = ["OTC Transitive Symbols"], - summary = "Add transitive OTC symbols", + summary = "Add transitive symbols", description = """ -Adds transitive symbols used for OTC route calculation. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Request body: Symbols -- symbols: Array, nullable - -Response body: -- No response body. - """, + POST /opex/v1/otc/transitive-symbols. + Bearer admin-token required. Required authority: ROLE_admin. + """, security = [SecurityRequirement(name = "bearerAuth")], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - description = "Transitive symbols payload.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Transitive symbols request", - value = """ -{ - "symbols": [ - "USDT", - "IRR" - ] -} - """ - ) - ] - ) - ] - ), responses = [ - ApiResponse( - responseCode = "200", - description = "Transitive symbols added successfully. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun addTransitiveSymbols( @@ -688,65 +210,16 @@ Response body: @DeleteMapping("/transitive-symbols/{symbol}") @Operation( - tags = ["OTC Transitive Symbols"], - summary = "Delete one transitive OTC symbol", + summary = "Delete transitive symbols", description = """ -Deletes one transitive symbol used for OTC route calculation. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Path parameters: -- symbol: symbol to delete. - -Response body: Symbols -- symbols: Array, nullable - """, + DELETE /opex/v1/otc/transitive-symbols/{symbol}. + Bearer admin-token required. Required authority: ROLE_admin. + """, security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter( - name = "symbol", - `in` = ParameterIn.PATH, - required = true, - description = "Transitive symbol to delete.", - example = "USDT", - schema = Schema(type = "string") - ) - ], responses = [ - ApiResponse( - responseCode = "200", - description = "Transitive symbol deleted successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Symbols response", - value = """ -{ - "symbols": [ - "IRR" - ] -} - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Symbols::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun deleteTransitiveSymbols( @@ -759,78 +232,16 @@ Response body: Symbols @DeleteMapping("/transitive-symbols") @Operation( - tags = ["OTC Transitive Symbols"], - summary = "Delete multiple transitive OTC symbols", + summary = "Delete transitive symbols", description = """ -Deletes multiple transitive symbols used for OTC route calculation. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Request body: Symbols -- symbols: Array, nullable - -Response body: Symbols -- symbols: Array, nullable - """, + DELETE /opex/v1/otc/transitive-symbols. + Bearer admin-token required. Required authority: ROLE_admin. + """, security = [SecurityRequirement(name = "bearerAuth")], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - description = "Transitive symbols delete payload.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Delete transitive symbols request", - value = """ -{ - "symbols": [ - "USDT", - "IRR" - ] -} - """ - ) - ] - ) - ] - ), responses = [ - ApiResponse( - responseCode = "200", - description = "Transitive symbols deleted successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Symbols response", - value = """ -{ - "symbols": [ - "USDT" - ] -} - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Symbols::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun deleteTransitiveSymbols( @@ -843,41 +254,12 @@ Response body: Symbols @GetMapping("/transitive-symbols") @Operation( - tags = ["OTC Transitive Symbols"], - summary = "List transitive OTC symbols", + summary = "Fetch transitive symbols", description = """ -Returns transitive symbols used for OTC route calculation. - -Authentication: -- Public endpoint. No Bearer token is required. - -Response body: Symbols -- symbols: Array, nullable - """, + GET /opex/v1/otc/transitive-symbols. + """, responses = [ - ApiResponse( - responseCode = "200", - description = "Transitive symbols returned successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Symbols response", - value = """ -{ - "symbols": [ - "USDT", - "IRR" - ] -} - """ - ) - ] - ) - ] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Symbols::class))]) ] ) suspend fun fetchTransitiveSymbols(): Symbols { @@ -887,80 +269,13 @@ Response body: Symbols // Routes and prices @GetMapping("/route") @Operation( - tags = ["OTC Routes & Prices"], - summary = "Calculate OTC exchange routes", + summary = "Fetch routes", description = """ -Returns calculated OTC exchange routes. - -Authentication: -- Public endpoint. No Bearer token is required. - -Query parameters: -- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. -- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. - -Route calculation behavior: -- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. -- If sourceSymbol is omitted, routes are calculated from all possible source symbols. -- If destSymbol is omitted, routes are calculated to all possible destination symbols. -- If both are omitted, routes are calculated for all possible symbol combinations. -- Do not send the literal string "null". Omit the query parameter when it should be treated as null. - -Response body: CurrencyExchangeRatesResponse -- rates: Array - -CurrencyExchangeRate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- isSwappable: boolean - """, - parameters = [ - Parameter( - name = "sourceSymbol", - `in` = ParameterIn.QUERY, - required = false, - description = "Optional source currency symbol. If omitted, all possible source symbols are considered. Do not send the literal string \"null\".", - example = "BTC", - schema = Schema(type = "string") - ), - Parameter( - name = "destSymbol", - `in` = ParameterIn.QUERY, - required = false, - description = "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Do not send the literal string \"null\".", - example = "USDT", - schema = Schema(type = "string") - ) - ], + GET /opex/v1/otc/route. + Optional sourceSymbol and destSymbol behavior: omit sourceSymbol to include all source symbols; omit destSymbol to include all destination symbols; omit both to calculate all possible symbol combinations. Do not send the literal string "null". + """, responses = [ - ApiResponse( - responseCode = "200", - description = "OTC exchange routes returned successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = CurrencyExchangeRatesResponse::class), - examples = [ - ExampleObject( - name = "Currency exchange routes response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00, - "isSwappable": true - } - ] -} - """ - ) - ] - ) - ] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyExchangeRatesResponse::class))]) ] ) suspend fun fetchRoutes( @@ -972,95 +287,17 @@ CurrencyExchangeRate item: @PostMapping("/route") @Operation( - tags = ["OTC Routes & Prices"], - summary = "Calculate OTC exchange routes as admin", + summary = "Fetch routes as admin", description = """ -Returns calculated OTC exchange routes. - -Required authentication: -- Bearer admin-token is required. -- Required role: ROLE_admin. - -Query parameters: -- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. -- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. - -Route calculation behavior: -- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. -- If sourceSymbol is omitted, routes are calculated from all possible source symbols. -- If destSymbol is omitted, routes are calculated to all possible destination symbols. -- If both are omitted, routes are calculated for all possible symbol combinations. -- Do not send the literal string "null". Omit the query parameter when it should be treated as null. - -Request body: -- No request body. - -Response body: CurrencyExchangeRatesResponse -- rates: Array - -CurrencyExchangeRate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- isSwappable: boolean - """, + POST /opex/v1/otc/route. + Bearer admin-token required. Required authority: ROLE_admin. + Optional sourceSymbol and destSymbol behavior: omit sourceSymbol to include all source symbols; omit destSymbol to include all destination symbols; omit both to calculate all possible symbol combinations. Do not send the literal string "null". + """, security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter( - name = "sourceSymbol", - `in` = ParameterIn.QUERY, - required = false, - description = "Optional source currency symbol. If omitted, all possible source symbols are considered. Do not send the literal string \"null\".", - example = "BTC", - schema = Schema(type = "string") - ), - Parameter( - name = "destSymbol", - `in` = ParameterIn.QUERY, - required = false, - description = "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Do not send the literal string \"null\".", - example = "USDT", - schema = Schema(type = "string") - ) - ], responses = [ - ApiResponse( - responseCode = "200", - description = "OTC exchange routes returned successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = CurrencyExchangeRatesResponse::class), - examples = [ - ExampleObject( - name = "Currency exchange routes response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00, - "isSwappable": true - } - ] -} - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required role is missing: ROLE_admin. No response body.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyExchangeRatesResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun fetchRoutesAsAdmin( @@ -1072,58 +309,12 @@ CurrencyExchangeRate item: @GetMapping("/currency/price") @Operation( - tags = ["OTC Routes & Prices"], - summary = "Get OTC currency prices", + summary = "Get price", description = """ -Returns OTC currency prices for the requested unit. - -Authentication: -- Public endpoint. No Bearer token is required. - -Query parameters: -- unit: pricing unit. - -Response body: Array -Each item: -- currency: string -- buyPrice: BigDecimal, nullable -- sellPrice: BigDecimal, nullable - """, - parameters = [ - Parameter( - name = "unit", - `in` = ParameterIn.QUERY, - required = true, - description = "Pricing unit.", - example = "USDT", - schema = Schema(type = "string") - ) - ], + GET /opex/v1/otc/currency/price. + """, responses = [ - ApiResponse( - responseCode = "200", - description = "Currency prices returned successfully.", - content = [ - Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = CurrencyPrice::class)), - examples = [ - ExampleObject( - name = "Currency price list response", - value = """ -[ - { - "currency": "BTC", - "buyPrice": 65000.00, - "sellPrice": 65100.00 - } -] - """ - ) - ] - ) - ] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyPrice::class)))]) ] ) suspend fun getPrice( From fcd69562e3a59cb65a51f837535894349549d633 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 12:08:27 +0330 Subject: [PATCH 11/56] Update swagger data about bank-account services --- .../opex/controller/BankAccountController.kt | 200 ++---------------- 1 file changed, 23 insertions(+), 177 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt index c03bbae3b..8b11bf23e 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -5,26 +5,21 @@ import co.nilin.opex.api.core.inout.BankAccountResponse import co.nilin.opex.api.core.spi.ProfileProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/bank-account") -@Tag( - name = "Bank Account", - description = "Manage authenticated user's bank accounts." -) +@Tag(name = "Bank Account", description = "Manage authenticated user's bank accounts.") class BankAccountController( val profileProxy: ProfileProxy, ) { @@ -33,88 +28,14 @@ class BankAccountController( @Operation( summary = "Add bank account", description = """ -Creates a new bank account for the authenticated user. - -Required authentication: -- Bearer JWT -- Required authority: PERM_bank_account:write - -Request body: AddBankAccountRequest -- name: string, nullable -- cardNumber: string, nullable -- iban: string, nullable - - -Response body: BankAccountResponse -- id: Long, nullable -- name: string, nullable -- cardNumber: string, nullable -- iban: string, nullable -- accountNumber: string, nullable -- bank: string, nullable -- status: WAITING | VERIFIED | REJECTED - """, + POST /opex/v1/bank-account. + Bearer user-token required. Requires authenticated user JWT. + Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid. + """, security = [SecurityRequirement(name = "bearerAuth")], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - description = "Bank account creation payload, Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = AddBankAccountRequest::class), - examples = [ - ExampleObject( - name = "Add bank account request", - value = """ -{ - "name": "My Bank Account", - "cardNumber": "6037991234567890", - "iban": null -} - """ - ) - ] - ) - ] - ), responses = [ - ApiResponse( - responseCode = "200", - description = "Bank account created successfully.", - content = [ - Content( - mediaType = "application/json", - schema = Schema(implementation = BankAccountResponse::class), - examples = [ - ExampleObject( - name = "Bank account response", - value = """ -{ - "id": 1, - "name": "My Bank Account", - "cardNumber": "6037991234567890", - "iban": "IR123456789012345678901234", - "accountNumber": null, - "bank": null, - "status": "WAITING" -} - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired.", - content = [Content()] - - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required authority is missing: PERM_bank_account:write.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) ] ) suspend fun addBankAccount( @@ -127,60 +48,15 @@ Response body: BankAccountResponse @GetMapping @Operation( - summary = "List bank accounts", + summary = "Get bank accounts", description = """ -Returns bank accounts for the authenticated user. - -Required authentication: -- Bearer JWT - -Response body: Array -Each item: -- id: Long, nullable -- name: string, nullable -- cardNumber: string, nullable -- iban: string, nullable -- accountNumber: string, nullable -- bank: string, nullable -- status: WAITING | VERIFIED | REJECTED - """, + GET /opex/v1/bank-account. + Bearer user-token required. Requires authenticated user JWT. + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse( - responseCode = "200", - description = "Bank accounts returned successfully.", - content = [ - Content( - mediaType = "application/json", - array = ArraySchema( - schema = Schema(implementation = BankAccountResponse::class) - ), - examples = [ - ExampleObject( - name = "Bank account list response", - value = """ -[ - { - "id": 1, - "name": "My Bank Account", - "cardNumber": "6037991234567890", - "iban": "IR123456789012345678901234", - "accountNumber": null, - "bank": null, - "status": "WAITING" - } -] - """ - ) - ] - ) - ] - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) ] ) suspend fun getBankAccounts( @@ -194,44 +70,14 @@ Each item: @Operation( summary = "Delete bank account", description = """ -Deletes one bank account by ID for the authenticated user. - -Required authentication: -- Bearer JWT -- Required authority: PERM_bank_account:write - -Path parameters: -- id: Bank account ID. - -Response body: -- No response body. - """, + DELETE /opex/v1/bank-account/{id}. + Bearer user-token required. Required authority: PERM_bank_account:write. + """, security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter( - name = "id", - `in` = ParameterIn.PATH, - required = true, - description = "Bank account ID.", - schema = Schema(type = "integer", format = "int64"), - example = "1" - ) - ], responses = [ - ApiResponse( - responseCode = "200", - description = "Bank account deleted successfully. No response body." - ), - ApiResponse( - responseCode = "401", - description = "Unauthorized. Bearer token is missing, invalid, or expired.", - content = [Content()] - ), - ApiResponse( - responseCode = "403", - description = "Forbidden. Required authority is missing: PERM_bank_account:write.", - content = [Content()] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_bank_account:write. No response body.", content = [Content()]) ] ) suspend fun deleteBankAccount( @@ -241,4 +87,4 @@ Response body: ) { profileProxy.deleteBankAccount(securityContext.jwtAuthentication().tokenValue(), id) } -} \ No newline at end of file +} From 26b7ebd181b0ae3ef16147efaf9019130a49ce6d Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 12:09:28 +0330 Subject: [PATCH 12/56] Update swagger data about deposit admin services --- .../opex/controller/DepositAdminController.kt | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt index 9ae00782d..6f379e746 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt @@ -9,18 +9,41 @@ import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* import java.math.BigDecimal +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/deposit") +@Tag(name = "Deposit Admin", description = "Admin manual deposit operations.") class DepositAdminController( private val walletProxy: WalletProxy, ) { @PostMapping("/manually/{amount}_{symbol}/{receiverUuid}") + @Operation( + summary = "Deposit manually", + description = """ + POST /opex/v1/admin/deposit/manually/{amount}_{symbol}/{receiverUuid}. + Bearer admin-token required. Required authority: ROLE_admin. + """, + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun depositManually( @PathVariable("symbol") symbol: String, @PathVariable("receiverUuid") receiverUuid: String, @PathVariable("amount") amount: BigDecimal, @RequestBody request: ManualTransferRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): TransferResult { return walletProxy.depositManually( @@ -32,4 +55,4 @@ class DepositAdminController( ) } -} \ No newline at end of file +} From 5cf255e8a3815c4f269d0ebad5a92508b8380654 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 12:19:27 +0330 Subject: [PATCH 13/56] Update swagger data about deposit services --- .../opex/controller/DepositController.kt | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt index 930441184..c0ac9540c 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt @@ -3,36 +3,39 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.RequestDepositBody import co.nilin.opex.api.core.inout.TransferResult import co.nilin.opex.api.core.spi.WalletProxy +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/deposit") -@Tag(name = "Deposit", description = "Deposit operations") +@Tag(name = "Deposit", description = "Authenticated deposit operations.") class DepositController(private val walletProxy: WalletProxy) { @PostMapping @Operation( - summary = "Request deposit", - description = "Submit a deposit request. Security handling is upstream (NEEDS REVIEW).", - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - content = [Content(mediaType = "application/json", schema = Schema(implementation = RequestDepositBody::class))] - ), + summary = "Deposit", + description = """ + POST /opex/v1/deposit. + Bearer user-token required. Required authority: PERM_deposit:write. + """, + security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class)) - ]) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_deposit:write. No response body.", content = [Content()]) ] ) suspend fun deposit(@RequestBody request: RequestDepositBody): TransferResult? { return walletProxy.deposit(request) } -} \ No newline at end of file +} From b6a37ea462015c4a15ff6b96296bfae662f9ce60 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 12:54:09 +0330 Subject: [PATCH 14/56] Update swagger data about address book services --- .../opex/controller/AddressBookController.kt | 77 +++++++------------ 1 file changed, 27 insertions(+), 50 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt index a02dcb1f1..c66609c2c 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt @@ -30,7 +30,7 @@ import org.springframework.web.bind.annotation.RestController @RequestMapping("/opex/v1/address-book") @Tag( name = "Address Book", - description = "Manage authenticated user's address book entries." + description = "Manage authenticated user's saved destination addresses." ) class AddressBookController( val profileProxy: ProfileProxy, @@ -38,28 +38,20 @@ class AddressBookController( @PostMapping @Operation( - summary = "Add address book entry", + summary = "Create address book entry", description = """ Creates a new address book entry for the authenticated user. -Required authentication: -- Bearer JWT +Security: +- Bearer user-token is required. -Request body: AddAddressBookItemRequest -- name: string, required -- address: string, required -- addressType: string, required - -Notes: -- addressType is a server-provided string value. -- Clients should use the exact value returned by the related chain/address-type source service. -- Do not treat addressType as a fixed enum and do not hardcode a static value list. +Validation: +- `name`, `address`, and `addressType` are required. +- `addressType` is a server-provided string related to the selected chain/address type. +- Clients should use values returned by server APIs and should not hardcode a fixed enum list. -Response body: AddressBookResponse -- id: Long, nullable -- name: string -- address: string -- addressType: string +Request body: AddAddressBookItemRequest +Response 200: AddressBookResponse """, security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -129,15 +121,10 @@ Response body: AddressBookResponse description = """ Returns all address book entries for the authenticated user. -Required authentication: -- Bearer JWT +Security: +- Bearer user-token is required. -Response body: Array -Each item: -- id: Long, nullable -- name: string -- address: string -- addressType: string +Response 200: Array """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ @@ -147,9 +134,7 @@ Each item: content = [ Content( mediaType = "application/json", - array = ArraySchema( - schema = Schema(implementation = AddressBookResponse::class) - ), + array = ArraySchema(schema = Schema(implementation = AddressBookResponse::class)), examples = [ ExampleObject( name = "Address book list response", @@ -188,13 +173,13 @@ Each item: description = """ Deletes one address book entry by ID for the authenticated user. -Required authentication: -- Bearer JWT +Security: +- Bearer user-token is required. Path parameters: -- id: Address book entry ID. +- `id`: address book entry ID. -Response body: +Response 200: - No response body. """, security = [SecurityRequirement(name = "bearerAuth")], @@ -235,27 +220,19 @@ Response body: description = """ Updates one address book entry by ID for the authenticated user. -Required authentication: -- Bearer JWT +Security: +- Bearer user-token is required. + +Validation: +- `name`, `address`, and `addressType` are required. +- `addressType` is a server-provided string related to the selected chain/address type. +- Clients should use values returned by server APIs and should not hardcode a fixed enum list. Path parameters: -- id: Address book entry ID. +- `id`: address book entry ID. Request body: AddAddressBookItemRequest -- name: string, required -- address: string, required -- addressType: string, required - -Notes: -- addressType is a server-provided string value. -- Clients should use the exact value returned by the related chain/address-type source service. -- Do not treat addressType as a fixed enum and do not hardcode a static value list. - -Response body: AddressBookResponse -- id: Long, nullable -- name: string -- address: string -- addressType: string +Response 200: AddressBookResponse """, security = [SecurityRequirement(name = "bearerAuth")], parameters = [ From 66f71655a4eecc5784c80dbbe95e73daa8ce5f36 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 12:55:59 +0330 Subject: [PATCH 15/56] Update swagger data about currency rate services --- .../controller/CurrencyRatesController.kt | 1014 +++++++++++++++-- 1 file changed, 919 insertions(+), 95 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt index 47c537672..a1c2eaa68 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt @@ -1,24 +1,39 @@ package co.nilin.opex.api.ports.opex.controller -import co.nilin.opex.api.core.inout.otc.* +import co.nilin.opex.api.core.inout.otc.CurrencyExchangeRatesResponse +import co.nilin.opex.api.core.inout.otc.CurrencyPair +import co.nilin.opex.api.core.inout.otc.CurrencyPrice +import co.nilin.opex.api.core.inout.otc.ForbiddenPairs +import co.nilin.opex.api.core.inout.otc.Rate +import co.nilin.opex.api.core.inout.otc.Rates +import co.nilin.opex.api.core.inout.otc.SetCurrencyExchangeRateRequest +import co.nilin.opex.api.core.inout.otc.Symbols import co.nilin.opex.api.core.spi.RateProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement -import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/otc") -@Tag(name = "OTC / Currency Rates", description = "Manage OTC currency exchange rates, forbidden pairs, transitive symbols, routes, and currency prices.") class CurrencyRatesController( private val rateProxy: RateProxy ) { @@ -26,16 +41,68 @@ class CurrencyRatesController( // Rates @PostMapping("/rate") @Operation( - summary = "Create rate", + tags = ["OTC Rates"], + summary = "Create OTC exchange rate", description = """ - POST /opex/v1/otc/rate. - Bearer admin-token required. Required authority: ROLE_admin. - """, +Creates a new OTC exchange rate. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Validation: +- `rate` must be greater than zero. +- `sourceSymbol` and `destSymbol` must be different. + +Request body: SetCurrencyExchangeRateRequest +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- ignoreIfExist: boolean, nullable, default false + +Response body: +- No response body. + """, security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "OTC exchange rate creation payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), + examples = [ + ExampleObject( + name = "Create OTC rate request", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00, + "ignoreIfExist": false +} + """ + ) + ] + ) + ] + ), responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "OTC exchange rate created successfully. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun createRate( @@ -49,16 +116,94 @@ class CurrencyRatesController( @PutMapping("/rate") @Operation( - summary = "Update rate", + tags = ["OTC Rates"], + summary = "Update OTC exchange rate", description = """ - PUT /opex/v1/otc/rate. - Bearer admin-token required. Required authority: ROLE_admin or ROLE_rate_bot. - """, +Updates an existing OTC exchange rate. + +Required authentication: +- Bearer admin-token or service token is required. +- Required role: ROLE_admin or ROLE_rate_bot. + +Validation: +- `rate` must be greater than zero. +- `sourceSymbol` and `destSymbol` must be different. + +Request body: SetCurrencyExchangeRateRequest +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- ignoreIfExist: boolean, nullable, default false + +Response body: Rates +- rates: Array, nullable + +Rate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "OTC exchange rate update payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), + examples = [ + ExampleObject( + name = "Update OTC rate request", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65100.00, + "ignoreIfExist": false +} + """ + ) + ] + ) + ] + ), responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rates::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin or ROLE_rate_bot. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "OTC exchange rate updated successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rates::class), + examples = [ + ExampleObject( + name = "Rates response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65100.00 + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin or ROLE_rate_bot. No response body.", + content = [Content()] + ) ] ) suspend fun updateRate( @@ -72,16 +217,83 @@ class CurrencyRatesController( @DeleteMapping("/rate/{sourceSymbol}/{destSymbol}") @Operation( - summary = "Delete rate", + tags = ["OTC Rates"], + summary = "Delete OTC exchange rate", description = """ - DELETE /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}. - Bearer admin-token required. Required authority: ROLE_admin. - """, +Deletes an OTC exchange rate by source and destination symbols. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Path parameters: +- sourceSymbol: source currency symbol. +- destSymbol: destination currency symbol. + +Response body: Rates +- rates: Array, nullable + +Rate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Source currency symbol.", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Destination currency symbol.", + example = "USDT", + schema = Schema(type = "string") + ) + ], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rates::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "OTC exchange rate deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rates::class), + examples = [ + ExampleObject( + name = "Rates response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "ETH", + "destSymbol": "USDT", + "rate": 3200.00 + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun deleteRate( @@ -95,12 +307,49 @@ class CurrencyRatesController( @GetMapping("/rate") @Operation( - summary = "Fetch rates", + tags = ["OTC Rates"], + summary = "List OTC exchange rates", description = """ - GET /opex/v1/otc/rate. - """, +Returns configured OTC exchange rates. + +Authentication: +- Public endpoint. No Bearer token is required. + +Response body: Rates +- rates: Array, nullable + +Rate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rates::class))]) + ApiResponse( + responseCode = "200", + description = "OTC exchange rates returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rates::class), + examples = [ + ExampleObject( + name = "Rates response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00 + } + ] +} + """ + ) + ] + ) + ] + ) ] ) suspend fun fetchRates(): Rates { @@ -109,12 +358,64 @@ class CurrencyRatesController( @GetMapping("/rate/{sourceSymbol}/{destSymbol}") @Operation( - summary = "Fetch rate", + tags = ["OTC Rates"], + summary = "Get OTC exchange rate", description = """ - GET /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}. - """, +Returns one OTC exchange rate by source and destination symbols. + +Authentication: +- Public endpoint. No Bearer token is required. + +Path parameters: +- sourceSymbol: source currency symbol. +- destSymbol: destination currency symbol. + +Response body: Rate, nullable +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal + """, + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Source currency symbol.", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Destination currency symbol.", + example = "USDT", + schema = Schema(type = "string") + ) + ], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Rate::class))]) + ApiResponse( + responseCode = "200", + description = "OTC exchange rate returned successfully. Response may be null if no rate exists.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Rate::class), + examples = [ + ExampleObject( + name = "Rate response", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00 +} + """ + ) + ] + ) + ] + ) ] ) suspend fun fetchRate( @@ -127,16 +428,63 @@ class CurrencyRatesController( // Forbidden pairs @PostMapping("/forbidden-pairs") @Operation( - summary = "Add forbidden pair", + tags = ["OTC Forbidden Pairs"], + summary = "Add forbidden OTC pair", description = """ - POST /opex/v1/otc/forbidden-pairs. - Bearer admin-token required. Required authority: ROLE_admin. - """, +Adds a forbidden OTC currency pair. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Validation: +- `sourceSymbol` and `destSymbol` must be different. + +Request body: CurrencyPair +- sourceSymbol: string +- destSymbol: string + +Response body: +- No response body. + """, security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "Forbidden OTC pair payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = CurrencyPair::class), + examples = [ + ExampleObject( + name = "Forbidden pair request", + value = """ +{ + "sourceSymbol": "BTC", + "destSymbol": "IRR" +} + """ + ) + ] + ) + ] + ), responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Forbidden pair added successfully. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun addForbiddenPair( @@ -150,16 +498,81 @@ class CurrencyRatesController( @DeleteMapping("/forbidden-pairs/{sourceSymbol}/{destSymbol}") @Operation( - summary = "Delete forbidden pair", + tags = ["OTC Forbidden Pairs"], + summary = "Delete forbidden OTC pair", description = """ - DELETE /opex/v1/otc/forbidden-pairs/{sourceSymbol}/{destSymbol}. - Bearer admin-token required. Required authority: ROLE_admin. - """, +Deletes one forbidden OTC currency pair. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Path parameters: +- sourceSymbol: source currency symbol. +- destSymbol: destination currency symbol. + +Response body: ForbiddenPairs +- forbiddenPairs: Array, nullable + +ForbiddenPair item: +- sourceSymbol: string +- destinationSymbol: string + """, security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Source currency symbol.", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.PATH, + required = true, + description = "Destination currency symbol.", + example = "IRR", + schema = Schema(type = "string") + ) + ], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ForbiddenPairs::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Forbidden pair deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = ForbiddenPairs::class), + examples = [ + ExampleObject( + name = "Forbidden pairs response", + value = """ +{ + "forbiddenPairs": [ + { + "sourceSymbol": "ETH", + "destinationSymbol": "IRR" + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun deleteForbiddenPair( @@ -173,12 +586,47 @@ class CurrencyRatesController( @GetMapping("/forbidden-pairs") @Operation( - summary = "Fetch forbidden pairs", + tags = ["OTC Forbidden Pairs"], + summary = "List forbidden OTC pairs", description = """ - GET /opex/v1/otc/forbidden-pairs. - """, +Returns forbidden OTC currency pairs. + +Authentication: +- Public endpoint. No Bearer token is required. + +Response body: ForbiddenPairs +- forbiddenPairs: Array, nullable + +ForbiddenPair item: +- sourceSymbol: string +- destinationSymbol: string + """, responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ForbiddenPairs::class))]) + ApiResponse( + responseCode = "200", + description = "Forbidden OTC pairs returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = ForbiddenPairs::class), + examples = [ + ExampleObject( + name = "Forbidden pairs response", + value = """ +{ + "forbiddenPairs": [ + { + "sourceSymbol": "BTC", + "destinationSymbol": "IRR" + } + ] +} + """ + ) + ] + ) + ] + ) ] ) suspend fun fetchForbiddenPairs(): ForbiddenPairs { @@ -188,16 +636,61 @@ class CurrencyRatesController( // Transitive symbols @PostMapping("/transitive-symbols") @Operation( - summary = "Add transitive symbols", + tags = ["OTC Transitive Symbols"], + summary = "Add transitive OTC symbols", description = """ - POST /opex/v1/otc/transitive-symbols. - Bearer admin-token required. Required authority: ROLE_admin. - """, +Adds transitive symbols used for OTC route calculation. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Request body: Symbols +- symbols: Array, nullable + +Response body: +- No response body. + """, security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "Transitive symbols payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Transitive symbols request", + value = """ +{ + "symbols": [ + "USDT", + "IRR" + ] +} + """ + ) + ] + ) + ] + ), responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Transitive symbols added successfully. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun addTransitiveSymbols( @@ -210,16 +703,65 @@ class CurrencyRatesController( @DeleteMapping("/transitive-symbols/{symbol}") @Operation( - summary = "Delete transitive symbols", + tags = ["OTC Transitive Symbols"], + summary = "Delete one transitive OTC symbol", description = """ - DELETE /opex/v1/otc/transitive-symbols/{symbol}. - Bearer admin-token required. Required authority: ROLE_admin. - """, +Deletes one transitive symbol used for OTC route calculation. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Path parameters: +- symbol: symbol to delete. + +Response body: Symbols +- symbols: Array, nullable + """, security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "symbol", + `in` = ParameterIn.PATH, + required = true, + description = "Transitive symbol to delete.", + example = "USDT", + schema = Schema(type = "string") + ) + ], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Symbols::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Transitive symbol deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Symbols response", + value = """ +{ + "symbols": [ + "IRR" + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun deleteTransitiveSymbols( @@ -232,16 +774,78 @@ class CurrencyRatesController( @DeleteMapping("/transitive-symbols") @Operation( - summary = "Delete transitive symbols", + tags = ["OTC Transitive Symbols"], + summary = "Delete multiple transitive OTC symbols", description = """ - DELETE /opex/v1/otc/transitive-symbols. - Bearer admin-token required. Required authority: ROLE_admin. - """, +Deletes multiple transitive symbols used for OTC route calculation. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Request body: Symbols +- symbols: Array, nullable + +Response body: Symbols +- symbols: Array, nullable + """, security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + description = "Transitive symbols delete payload.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Delete transitive symbols request", + value = """ +{ + "symbols": [ + "USDT", + "IRR" + ] +} + """ + ) + ] + ) + ] + ), responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Symbols::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Transitive symbols deleted successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Symbols response", + value = """ +{ + "symbols": [ + "USDT" + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun deleteTransitiveSymbols( @@ -254,12 +858,41 @@ class CurrencyRatesController( @GetMapping("/transitive-symbols") @Operation( - summary = "Fetch transitive symbols", + tags = ["OTC Transitive Symbols"], + summary = "List transitive OTC symbols", description = """ - GET /opex/v1/otc/transitive-symbols. - """, +Returns transitive symbols used for OTC route calculation. + +Authentication: +- Public endpoint. No Bearer token is required. + +Response body: Symbols +- symbols: Array, nullable + """, responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Symbols::class))]) + ApiResponse( + responseCode = "200", + description = "Transitive symbols returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = Symbols::class), + examples = [ + ExampleObject( + name = "Symbols response", + value = """ +{ + "symbols": [ + "USDT", + "IRR" + ] +} + """ + ) + ] + ) + ] + ) ] ) suspend fun fetchTransitiveSymbols(): Symbols { @@ -269,13 +902,80 @@ class CurrencyRatesController( // Routes and prices @GetMapping("/route") @Operation( - summary = "Fetch routes", + tags = ["OTC Routes & Prices"], + summary = "Calculate OTC exchange routes", description = """ - GET /opex/v1/otc/route. - Optional sourceSymbol and destSymbol behavior: omit sourceSymbol to include all source symbols; omit destSymbol to include all destination symbols; omit both to calculate all possible symbol combinations. Do not send the literal string "null". - """, +Returns calculated OTC exchange routes. + +Authentication: +- Public endpoint. No Bearer token is required. + +Query parameters: +- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. +- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. + +Route calculation behavior: +- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. +- If sourceSymbol is omitted, routes are calculated from all possible source symbols. +- If destSymbol is omitted, routes are calculated to all possible destination symbols. +- If both are omitted, routes are calculated for all possible symbol combinations. +- Do not send the literal string "null". Omit the query parameter when it should be treated as null. + +Response body: CurrencyExchangeRatesResponse +- rates: Array + +CurrencyExchangeRate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- isSwappable: boolean + """, + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional source currency symbol. If omitted, all possible source symbols are considered. Do not send the literal string \"null\".", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Do not send the literal string \"null\".", + example = "USDT", + schema = Schema(type = "string") + ) + ], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyExchangeRatesResponse::class))]) + ApiResponse( + responseCode = "200", + description = "OTC exchange routes returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = CurrencyExchangeRatesResponse::class), + examples = [ + ExampleObject( + name = "Currency exchange routes response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00, + "isSwappable": true + } + ] +} + """ + ) + ] + ) + ] + ) ] ) suspend fun fetchRoutes( @@ -287,17 +987,95 @@ class CurrencyRatesController( @PostMapping("/route") @Operation( - summary = "Fetch routes as admin", + tags = ["OTC Routes & Prices"], + summary = "Calculate OTC exchange routes as admin", description = """ - POST /opex/v1/otc/route. - Bearer admin-token required. Required authority: ROLE_admin. - Optional sourceSymbol and destSymbol behavior: omit sourceSymbol to include all source symbols; omit destSymbol to include all destination symbols; omit both to calculate all possible symbol combinations. Do not send the literal string "null". - """, +Returns calculated OTC exchange routes. + +Required authentication: +- Bearer admin-token is required. +- Required role: ROLE_admin. + +Query parameters: +- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. +- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. + +Route calculation behavior: +- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. +- If sourceSymbol is omitted, routes are calculated from all possible source symbols. +- If destSymbol is omitted, routes are calculated to all possible destination symbols. +- If both are omitted, routes are calculated for all possible symbol combinations. +- Do not send the literal string "null". Omit the query parameter when it should be treated as null. + +Request body: +- No request body. + +Response body: CurrencyExchangeRatesResponse +- rates: Array + +CurrencyExchangeRate item: +- sourceSymbol: string +- destSymbol: string +- rate: BigDecimal +- isSwappable: boolean + """, security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "sourceSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional source currency symbol. If omitted, all possible source symbols are considered. Do not send the literal string \"null\".", + example = "BTC", + schema = Schema(type = "string") + ), + Parameter( + name = "destSymbol", + `in` = ParameterIn.QUERY, + required = false, + description = "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Do not send the literal string \"null\".", + example = "USDT", + schema = Schema(type = "string") + ) + ], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyExchangeRatesResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "OTC exchange routes returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = CurrencyExchangeRatesResponse::class), + examples = [ + ExampleObject( + name = "Currency exchange routes response", + value = """ +{ + "rates": [ + { + "sourceSymbol": "BTC", + "destSymbol": "USDT", + "rate": 65000.00, + "isSwappable": true + } + ] +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required role is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun fetchRoutesAsAdmin( @@ -309,12 +1087,58 @@ class CurrencyRatesController( @GetMapping("/currency/price") @Operation( - summary = "Get price", + tags = ["OTC Routes & Prices"], + summary = "Get OTC currency prices", description = """ - GET /opex/v1/otc/currency/price. - """, +Returns OTC currency prices for the requested unit. + +Authentication: +- Public endpoint. No Bearer token is required. + +Query parameters: +- unit: pricing unit. + +Response body: Array +Each item: +- currency: string +- buyPrice: BigDecimal, nullable +- sellPrice: BigDecimal, nullable + """, + parameters = [ + Parameter( + name = "unit", + `in` = ParameterIn.QUERY, + required = true, + description = "Pricing unit.", + example = "USDT", + schema = Schema(type = "string") + ) + ], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyPrice::class)))]) + ApiResponse( + responseCode = "200", + description = "Currency prices returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = CurrencyPrice::class)), + examples = [ + ExampleObject( + name = "Currency price list response", + value = """ +[ + { + "currency": "BTC", + "buyPrice": 65000.00, + "sellPrice": 65100.00 + } +] + """ + ) + ] + ) + ] + ) ] ) suspend fun getPrice( From 8d11704692fd63b01c6459aeca1e75857c8d8b08 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 13:21:14 +0330 Subject: [PATCH 16/56] Complete swagger description about address book services --- .../opex/controller/AddressBookController.kt | 137 ++---------------- 1 file changed, 16 insertions(+), 121 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt index c66609c2c..2455d3ca0 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/AddressBookController.kt @@ -10,7 +10,6 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement @@ -33,26 +32,16 @@ import org.springframework.web.bind.annotation.RestController description = "Manage authenticated user's saved destination addresses." ) class AddressBookController( - val profileProxy: ProfileProxy, + val profileProxy: ProfileProxy ) { @PostMapping @Operation( summary = "Create address book entry", - description = """ -Creates a new address book entry for the authenticated user. + description = """Creates a new address book entry for the authenticated user. +Security: Bearer user-token is required. -Security: -- Bearer user-token is required. - -Validation: -- `name`, `address`, and `addressType` are required. -- `addressType` is a server-provided string related to the selected chain/address type. -- Clients should use values returned by server APIs and should not hardcode a fixed enum list. - -Request body: AddAddressBookItemRequest -Response 200: AddressBookResponse - """, +Behavior: `addressType` is a server-provided string. Clients should use the value returned by the related chain/address-type service and must not hardcode a fixed enum list.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -60,19 +49,7 @@ Response 200: AddressBookResponse content = [ Content( mediaType = "application/json", - schema = Schema(implementation = AddAddressBookItemRequest::class), - examples = [ - ExampleObject( - name = "Create address book entry", - value = """ -{ - "name": "Home Wallet", - "address": "0x1234567890abcdef1234567890abcdef12345678", - "addressType": "ethereum" -} - """ - ) - ] + schema = Schema(implementation = AddAddressBookItemRequest::class) ) ] ), @@ -83,20 +60,7 @@ Response 200: AddressBookResponse content = [ Content( mediaType = "application/json", - schema = Schema(implementation = AddressBookResponse::class), - examples = [ - ExampleObject( - name = "Address book response", - value = """ -{ - "id": 1, - "name": "Home Wallet", - "address": "0x1234567890abcdef1234567890abcdef12345678", - "addressType": "ethereum" -} - """ - ) - ] + schema = Schema(implementation = AddressBookResponse::class) ) ] ), @@ -118,14 +82,8 @@ Response 200: AddressBookResponse @GetMapping @Operation( summary = "List address book entries", - description = """ -Returns all address book entries for the authenticated user. - -Security: -- Bearer user-token is required. - -Response 200: Array - """, + description = """Returns all address book entries for the authenticated user. +Security: Bearer user-token is required.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( @@ -134,22 +92,7 @@ Response 200: Array content = [ Content( mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = AddressBookResponse::class)), - examples = [ - ExampleObject( - name = "Address book list response", - value = """ -[ - { - "id": 1, - "name": "Home Wallet", - "address": "0x1234567890abcdef1234567890abcdef12345678", - "addressType": "ethereum" - } -] - """ - ) - ] + array = ArraySchema(schema = Schema(implementation = AddressBookResponse::class)) ) ] ), @@ -170,18 +113,8 @@ Response 200: Array @DeleteMapping("/{id}") @Operation( summary = "Delete address book entry", - description = """ -Deletes one address book entry by ID for the authenticated user. - -Security: -- Bearer user-token is required. - -Path parameters: -- `id`: address book entry ID. - -Response 200: -- No response body. - """, + description = """Deletes one address book entry by ID for the authenticated user. +Security: Bearer user-token is required.""", security = [SecurityRequirement(name = "bearerAuth")], parameters = [ Parameter( @@ -217,23 +150,10 @@ Response 200: @PutMapping("/{id}") @Operation( summary = "Update address book entry", - description = """ -Updates one address book entry by ID for the authenticated user. - -Security: -- Bearer user-token is required. - -Validation: -- `name`, `address`, and `addressType` are required. -- `addressType` is a server-provided string related to the selected chain/address type. -- Clients should use values returned by server APIs and should not hardcode a fixed enum list. + description = """Updates one address book entry by ID for the authenticated user. +Security: Bearer user-token is required. -Path parameters: -- `id`: address book entry ID. - -Request body: AddAddressBookItemRequest -Response 200: AddressBookResponse - """, +Behavior: `addressType` is a server-provided string. Clients should use the value returned by the related chain/address-type service and must not hardcode a fixed enum list.""", security = [SecurityRequirement(name = "bearerAuth")], parameters = [ Parameter( @@ -251,19 +171,7 @@ Response 200: AddressBookResponse content = [ Content( mediaType = "application/json", - schema = Schema(implementation = AddAddressBookItemRequest::class), - examples = [ - ExampleObject( - name = "Update address book entry", - value = """ -{ - "name": "Updated Wallet Name", - "address": "0x1234567890abcdef1234567890abcdef12345678", - "addressType": "ethereum" -} - """ - ) - ] + schema = Schema(implementation = AddAddressBookItemRequest::class) ) ] ), @@ -274,20 +182,7 @@ Response 200: AddressBookResponse content = [ Content( mediaType = "application/json", - schema = Schema(implementation = AddressBookResponse::class), - examples = [ - ExampleObject( - name = "Address book response", - value = """ -{ - "id": 1, - "name": "Updated Wallet Name", - "address": "0x1234567890abcdef1234567890abcdef12345678", - "addressType": "ethereum" -} - """ - ) - ] + schema = Schema(implementation = AddressBookResponse::class) ) ] ), From 232e2288181b800d177b748571ba82059a48ebd5 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 13:22:52 +0330 Subject: [PATCH 17/56] Update swagger data about bank-account services --- .../opex/controller/BankAccountController.kt | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt index 8b11bf23e..fd2150c23 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -21,20 +21,19 @@ import io.swagger.v3.oas.annotations.tags.Tag @RequestMapping("/opex/v1/bank-account") @Tag(name = "Bank Account", description = "Manage authenticated user's bank accounts.") class BankAccountController( - val profileProxy: ProfileProxy, + val profileProxy: ProfileProxy ) { @PostMapping @Operation( summary = "Add bank account", - description = """ - POST /opex/v1/bank-account. - Bearer user-token required. Requires authenticated user JWT. - Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid. - """, + description = """POST /opex/v1/bank-account. +Security: Bearer user-token required. Requires authenticated user JWT. + +Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class))]), + ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) ] ) @@ -49,13 +48,11 @@ class BankAccountController( @GetMapping @Operation( summary = "Get bank accounts", - description = """ - GET /opex/v1/bank-account. - Bearer user-token required. Requires authenticated user JWT. - """, + description = """GET /opex/v1/bank-account. +Security: Bearer user-token required. Requires authenticated user JWT.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class)))]), + ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class)))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) ] ) @@ -69,13 +66,11 @@ class BankAccountController( @DeleteMapping("/{id}") @Operation( summary = "Delete bank account", - description = """ - DELETE /opex/v1/bank-account/{id}. - Bearer user-token required. Required authority: PERM_bank_account:write. - """, + description = """DELETE /opex/v1/bank-account/{id}. +Security: Bearer user-token required. Required authority: PERM_bank_account:write.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content()]), + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_bank_account:write. No response body.", content = [Content()]) ] From 83358716b369cd5e71a174f5cb7054a367299fcc Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 13:23:27 +0330 Subject: [PATCH 18/56] Update swagger data about currency rate services --- .../controller/CurrencyRatesController.kt | 459 +++--------------- 1 file changed, 55 insertions(+), 404 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt index a1c2eaa68..e2a1d698d 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt @@ -16,7 +16,6 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement @@ -43,8 +42,7 @@ class CurrencyRatesController( @Operation( tags = ["OTC Rates"], summary = "Create OTC exchange rate", - description = """ -Creates a new OTC exchange rate. + description = """Creates a new OTC exchange rate. Required authentication: - Bearer admin-token is required. @@ -54,15 +52,9 @@ Validation: - `rate` must be greater than zero. - `sourceSymbol` and `destSymbol` must be different. -Request body: SetCurrencyExchangeRateRequest -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- ignoreIfExist: boolean, nullable, default false +Request body: SetCurrencyExchangeRateRequest. -Response body: -- No response body. - """, +Response body: See schema.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -70,20 +62,7 @@ Response body: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), - examples = [ - ExampleObject( - name = "Create OTC rate request", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00, - "ignoreIfExist": false -} - """ - ) - ] + schema = Schema(implementation = SetCurrencyExchangeRateRequest::class) ) ] ), @@ -118,8 +97,7 @@ Response body: @Operation( tags = ["OTC Rates"], summary = "Update OTC exchange rate", - description = """ -Updates an existing OTC exchange rate. + description = """Updates an existing OTC exchange rate. Required authentication: - Bearer admin-token or service token is required. @@ -129,20 +107,9 @@ Validation: - `rate` must be greater than zero. - `sourceSymbol` and `destSymbol` must be different. -Request body: SetCurrencyExchangeRateRequest -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- ignoreIfExist: boolean, nullable, default false - -Response body: Rates -- rates: Array, nullable +Request body: SetCurrencyExchangeRateRequest. -Rate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, +Response body: Rates.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -150,20 +117,7 @@ Rate item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = SetCurrencyExchangeRateRequest::class), - examples = [ - ExampleObject( - name = "Update OTC rate request", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65100.00, - "ignoreIfExist": false -} - """ - ) - ] + schema = Schema(implementation = SetCurrencyExchangeRateRequest::class) ) ] ), @@ -174,23 +128,7 @@ Rate item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Rates::class), - examples = [ - ExampleObject( - name = "Rates response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65100.00 - } - ] -} - """ - ) - ] + schema = Schema(implementation = Rates::class) ) ] ), @@ -219,25 +157,15 @@ Rate item: @Operation( tags = ["OTC Rates"], summary = "Delete OTC exchange rate", - description = """ -Deletes an OTC exchange rate by source and destination symbols. + description = """Deletes an OTC exchange rate by source and destination symbols. Required authentication: - Bearer admin-token is required. - Required role: ROLE_admin. Path parameters: -- sourceSymbol: source currency symbol. -- destSymbol: destination currency symbol. - -Response body: Rates -- rates: Array, nullable -Rate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, +Response body: Rates.""", security = [SecurityRequirement(name = "bearerAuth")], parameters = [ Parameter( @@ -264,23 +192,7 @@ Rate item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Rates::class), - examples = [ - ExampleObject( - name = "Rates response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "ETH", - "destSymbol": "USDT", - "rate": 3200.00 - } - ] -} - """ - ) - ] + schema = Schema(implementation = Rates::class) ) ] ), @@ -309,20 +221,12 @@ Rate item: @Operation( tags = ["OTC Rates"], summary = "List OTC exchange rates", - description = """ -Returns configured OTC exchange rates. + description = """Returns configured OTC exchange rates. Authentication: - Public endpoint. No Bearer token is required. -Response body: Rates -- rates: Array, nullable - -Rate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, +Response body: Rates.""", responses = [ ApiResponse( responseCode = "200", @@ -330,23 +234,7 @@ Rate item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Rates::class), - examples = [ - ExampleObject( - name = "Rates response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00 - } - ] -} - """ - ) - ] + schema = Schema(implementation = Rates::class) ) ] ) @@ -360,21 +248,14 @@ Rate item: @Operation( tags = ["OTC Rates"], summary = "Get OTC exchange rate", - description = """ -Returns one OTC exchange rate by source and destination symbols. + description = """Returns one OTC exchange rate by source and destination symbols. Authentication: - Public endpoint. No Bearer token is required. Path parameters: -- sourceSymbol: source currency symbol. -- destSymbol: destination currency symbol. - -Response body: Rate, nullable -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal - """, + +Response body: Rate, nullable.""", parameters = [ Parameter( name = "sourceSymbol", @@ -400,19 +281,7 @@ Response body: Rate, nullable content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Rate::class), - examples = [ - ExampleObject( - name = "Rate response", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00 -} - """ - ) - ] + schema = Schema(implementation = Rate::class) ) ] ) @@ -430,8 +299,7 @@ Response body: Rate, nullable @Operation( tags = ["OTC Forbidden Pairs"], summary = "Add forbidden OTC pair", - description = """ -Adds a forbidden OTC currency pair. + description = """Adds a forbidden OTC currency pair. Required authentication: - Bearer admin-token is required. @@ -440,13 +308,9 @@ Required authentication: Validation: - `sourceSymbol` and `destSymbol` must be different. -Request body: CurrencyPair -- sourceSymbol: string -- destSymbol: string +Request body: CurrencyPair. -Response body: -- No response body. - """, +Response body: See schema.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -454,18 +318,7 @@ Response body: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = CurrencyPair::class), - examples = [ - ExampleObject( - name = "Forbidden pair request", - value = """ -{ - "sourceSymbol": "BTC", - "destSymbol": "IRR" -} - """ - ) - ] + schema = Schema(implementation = CurrencyPair::class) ) ] ), @@ -500,24 +353,15 @@ Response body: @Operation( tags = ["OTC Forbidden Pairs"], summary = "Delete forbidden OTC pair", - description = """ -Deletes one forbidden OTC currency pair. + description = """Deletes one forbidden OTC currency pair. Required authentication: - Bearer admin-token is required. - Required role: ROLE_admin. Path parameters: -- sourceSymbol: source currency symbol. -- destSymbol: destination currency symbol. -Response body: ForbiddenPairs -- forbiddenPairs: Array, nullable - -ForbiddenPair item: -- sourceSymbol: string -- destinationSymbol: string - """, +Response body: ForbiddenPairs.""", security = [SecurityRequirement(name = "bearerAuth")], parameters = [ Parameter( @@ -544,22 +388,7 @@ ForbiddenPair item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = ForbiddenPairs::class), - examples = [ - ExampleObject( - name = "Forbidden pairs response", - value = """ -{ - "forbiddenPairs": [ - { - "sourceSymbol": "ETH", - "destinationSymbol": "IRR" - } - ] -} - """ - ) - ] + schema = Schema(implementation = ForbiddenPairs::class) ) ] ), @@ -588,19 +417,12 @@ ForbiddenPair item: @Operation( tags = ["OTC Forbidden Pairs"], summary = "List forbidden OTC pairs", - description = """ -Returns forbidden OTC currency pairs. + description = """Returns forbidden OTC currency pairs. Authentication: - Public endpoint. No Bearer token is required. -Response body: ForbiddenPairs -- forbiddenPairs: Array, nullable - -ForbiddenPair item: -- sourceSymbol: string -- destinationSymbol: string - """, +Response body: ForbiddenPairs.""", responses = [ ApiResponse( responseCode = "200", @@ -608,22 +430,7 @@ ForbiddenPair item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = ForbiddenPairs::class), - examples = [ - ExampleObject( - name = "Forbidden pairs response", - value = """ -{ - "forbiddenPairs": [ - { - "sourceSymbol": "BTC", - "destinationSymbol": "IRR" - } - ] -} - """ - ) - ] + schema = Schema(implementation = ForbiddenPairs::class) ) ] ) @@ -638,19 +445,15 @@ ForbiddenPair item: @Operation( tags = ["OTC Transitive Symbols"], summary = "Add transitive OTC symbols", - description = """ -Adds transitive symbols used for OTC route calculation. + description = """Adds transitive symbols used for OTC route calculation. Required authentication: - Bearer admin-token is required. - Required role: ROLE_admin. -Request body: Symbols -- symbols: Array, nullable +Request body: Symbols. -Response body: -- No response body. - """, +Response body: See schema.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -658,20 +461,7 @@ Response body: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Transitive symbols request", - value = """ -{ - "symbols": [ - "USDT", - "IRR" - ] -} - """ - ) - ] + schema = Schema(implementation = Symbols::class) ) ] ), @@ -705,19 +495,15 @@ Response body: @Operation( tags = ["OTC Transitive Symbols"], summary = "Delete one transitive OTC symbol", - description = """ -Deletes one transitive symbol used for OTC route calculation. + description = """Deletes one transitive symbol used for OTC route calculation. Required authentication: - Bearer admin-token is required. - Required role: ROLE_admin. Path parameters: -- symbol: symbol to delete. -Response body: Symbols -- symbols: Array, nullable - """, +Response body: Symbols.""", security = [SecurityRequirement(name = "bearerAuth")], parameters = [ Parameter( @@ -736,19 +522,7 @@ Response body: Symbols content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Symbols response", - value = """ -{ - "symbols": [ - "IRR" - ] -} - """ - ) - ] + schema = Schema(implementation = Symbols::class) ) ] ), @@ -776,19 +550,15 @@ Response body: Symbols @Operation( tags = ["OTC Transitive Symbols"], summary = "Delete multiple transitive OTC symbols", - description = """ -Deletes multiple transitive symbols used for OTC route calculation. + description = """Deletes multiple transitive symbols used for OTC route calculation. Required authentication: - Bearer admin-token is required. - Required role: ROLE_admin. -Request body: Symbols -- symbols: Array, nullable +Request body: Symbols. -Response body: Symbols -- symbols: Array, nullable - """, +Response body: Symbols.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -796,20 +566,7 @@ Response body: Symbols content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Delete transitive symbols request", - value = """ -{ - "symbols": [ - "USDT", - "IRR" - ] -} - """ - ) - ] + schema = Schema(implementation = Symbols::class) ) ] ), @@ -820,19 +577,7 @@ Response body: Symbols content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Symbols response", - value = """ -{ - "symbols": [ - "USDT" - ] -} - """ - ) - ] + schema = Schema(implementation = Symbols::class) ) ] ), @@ -860,15 +605,12 @@ Response body: Symbols @Operation( tags = ["OTC Transitive Symbols"], summary = "List transitive OTC symbols", - description = """ -Returns transitive symbols used for OTC route calculation. + description = """Returns transitive symbols used for OTC route calculation. Authentication: - Public endpoint. No Bearer token is required. -Response body: Symbols -- symbols: Array, nullable - """, +Response body: Symbols.""", responses = [ ApiResponse( responseCode = "200", @@ -876,20 +618,7 @@ Response body: Symbols content = [ Content( mediaType = "application/json", - schema = Schema(implementation = Symbols::class), - examples = [ - ExampleObject( - name = "Symbols response", - value = """ -{ - "symbols": [ - "USDT", - "IRR" - ] -} - """ - ) - ] + schema = Schema(implementation = Symbols::class) ) ] ) @@ -904,15 +633,12 @@ Response body: Symbols @Operation( tags = ["OTC Routes & Prices"], summary = "Calculate OTC exchange routes", - description = """ -Returns calculated OTC exchange routes. + description = """Returns calculated OTC exchange routes. Authentication: - Public endpoint. No Bearer token is required. Query parameters: -- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. -- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. Route calculation behavior: - If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. @@ -921,15 +647,7 @@ Route calculation behavior: - If both are omitted, routes are calculated for all possible symbol combinations. - Do not send the literal string "null". Omit the query parameter when it should be treated as null. -Response body: CurrencyExchangeRatesResponse -- rates: Array - -CurrencyExchangeRate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- isSwappable: boolean - """, +Response body: CurrencyExchangeRatesResponse.""", parameters = [ Parameter( name = "sourceSymbol", @@ -955,24 +673,7 @@ CurrencyExchangeRate item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = CurrencyExchangeRatesResponse::class), - examples = [ - ExampleObject( - name = "Currency exchange routes response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00, - "isSwappable": true - } - ] -} - """ - ) - ] + schema = Schema(implementation = CurrencyExchangeRatesResponse::class) ) ] ) @@ -989,16 +690,13 @@ CurrencyExchangeRate item: @Operation( tags = ["OTC Routes & Prices"], summary = "Calculate OTC exchange routes as admin", - description = """ -Returns calculated OTC exchange routes. + description = """Returns calculated OTC exchange routes. Required authentication: - Bearer admin-token is required. - Required role: ROLE_admin. Query parameters: -- sourceSymbol: optional source currency symbol. If omitted, all possible source symbols are considered. -- destSymbol: optional destination currency symbol. If omitted, all possible destination symbols are considered. Route calculation behavior: - If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair. @@ -1007,18 +705,9 @@ Route calculation behavior: - If both are omitted, routes are calculated for all possible symbol combinations. - Do not send the literal string "null". Omit the query parameter when it should be treated as null. -Request body: -- No request body. +Request body: See schema. -Response body: CurrencyExchangeRatesResponse -- rates: Array - -CurrencyExchangeRate item: -- sourceSymbol: string -- destSymbol: string -- rate: BigDecimal -- isSwappable: boolean - """, +Response body: CurrencyExchangeRatesResponse.""", security = [SecurityRequirement(name = "bearerAuth")], parameters = [ Parameter( @@ -1045,24 +734,7 @@ CurrencyExchangeRate item: content = [ Content( mediaType = "application/json", - schema = Schema(implementation = CurrencyExchangeRatesResponse::class), - examples = [ - ExampleObject( - name = "Currency exchange routes response", - value = """ -{ - "rates": [ - { - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "rate": 65000.00, - "isSwappable": true - } - ] -} - """ - ) - ] + schema = Schema(implementation = CurrencyExchangeRatesResponse::class) ) ] ), @@ -1089,21 +761,14 @@ CurrencyExchangeRate item: @Operation( tags = ["OTC Routes & Prices"], summary = "Get OTC currency prices", - description = """ -Returns OTC currency prices for the requested unit. + description = """Returns OTC currency prices for the requested unit. Authentication: - Public endpoint. No Bearer token is required. Query parameters: -- unit: pricing unit. - -Response body: Array -Each item: -- currency: string -- buyPrice: BigDecimal, nullable -- sellPrice: BigDecimal, nullable - """, + +Response body: Array.""", parameters = [ Parameter( name = "unit", @@ -1121,21 +786,7 @@ Each item: content = [ Content( mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = CurrencyPrice::class)), - examples = [ - ExampleObject( - name = "Currency price list response", - value = """ -[ - { - "currency": "BTC", - "buyPrice": 65000.00, - "sellPrice": 65100.00 - } -] - """ - ) - ] + array = ArraySchema(schema = Schema(implementation = CurrencyPrice::class)) ) ] ) From cdaaf5117a618946d546963b21f50efa22e8031d Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 13:24:21 +0330 Subject: [PATCH 19/56] Update swagger data about deposit admin services --- .../ports/opex/controller/DepositAdminController.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt index 6f379e746..1a4c07cf7 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt @@ -22,18 +22,16 @@ import io.swagger.v3.oas.annotations.tags.Tag @RequestMapping("/opex/v1/admin/deposit") @Tag(name = "Deposit Admin", description = "Admin manual deposit operations.") class DepositAdminController( - private val walletProxy: WalletProxy, + private val walletProxy: WalletProxy ) { @PostMapping("/manually/{amount}_{symbol}/{receiverUuid}") @Operation( summary = "Deposit manually", - description = """ - POST /opex/v1/admin/deposit/manually/{amount}_{symbol}/{receiverUuid}. - Bearer admin-token required. Required authority: ROLE_admin. - """, + description = """POST /opex/v1/admin/deposit/manually/{amount}_{symbol}/{receiverUuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] From 241ac08985c259059983ab3779042438f321fe15 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 14:57:27 +0330 Subject: [PATCH 20/56] Update swagger data about bank-account services --- .../opex/controller/BankAccountController.kt | 4 +- .../opex/controller/DepositController.kt | 10 +-- .../opex/controller/GatewayAdminController.kt | 73 ++++++++++++++++++- 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt index fd2150c23..93e159b19 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -33,7 +33,7 @@ Security: Bearer user-token required. Requires authenticated user JWT. Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class))]), + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) ] ) @@ -52,7 +52,7 @@ Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing bo Security: Bearer user-token required. Requires authenticated user JWT.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class)))]), + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class)))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) ] ) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt index c0ac9540c..831aa83d3 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt @@ -24,13 +24,13 @@ class DepositController(private val walletProxy: WalletProxy) { @PostMapping @Operation( summary = "Deposit", - description = """ - POST /opex/v1/deposit. - Bearer user-token required. Required authority: PERM_deposit:write. - """, + description = """POST /opex/v1/deposit. +Security: Bearer user-token required. Required authority: PERM_deposit:write. + +Behavior: Use gatewayUuid/chain when the deposit flow requires a specific gateway or network. The receiver wallet type must be one of the server-supported wallet types.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_deposit:write. No response body.", content = [Content()]) ] diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt index 8b82f11c0..7eed711d5 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt @@ -7,24 +7,61 @@ import co.nilin.opex.api.ports.opex.util.tokenValue import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin") +@Tag(name = "Gateway Admin", description = "Admin gateway management for currencies.") class GatewayAdminController( - private val walletProxy: WalletProxy, + private val walletProxy: WalletProxy ) { @PostMapping("/{currencySymbol}/gateway") + @Operation( + summary = "Add currency to gateway", + description = """POST /opex/v1/admin/{currencySymbol}/gateway. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyGatewayCommand::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun addCurrencyToGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currencySymbol") currencySymbol: String, - @RequestBody body: CurrencyGatewayCommand, + @RequestBody body: CurrencyGatewayCommand ): CurrencyGatewayCommand? { return walletProxy.addCurrencyToGateway(securityContext.jwtAuthentication().tokenValue(), currencySymbol, body) } @PutMapping("/{currencySymbol}/gateway/{uuid}") + @Operation( + summary = "Update gateway", + description = """PUT /opex/v1/admin/{currencySymbol}/gateway/{uuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyGatewayCommand::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun updateGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, @@ -39,10 +76,24 @@ class GatewayAdminController( } @GetMapping("/{currencySymbol}/gateway/{uuid}") + @Operation( + summary = "Get gateway", + description = """GET /opex/v1/admin/{currencySymbol}/gateway/{uuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyGatewayCommand::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, - @PathVariable("currencySymbol") currencySymbol: String, + @PathVariable("currencySymbol") currencySymbol: String ): CurrencyGatewayCommand? { return walletProxy.getGateway( securityContext.jwtAuthentication().tokenValue(), @@ -52,10 +103,24 @@ class GatewayAdminController( } @DeleteMapping("/{currencySymbol}/gateway/{uuid}") + @Operation( + summary = "Delete gateway", + description = """DELETE /opex/v1/admin/{currencySymbol}/gateway/{uuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun deleteGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, - @PathVariable("currencySymbol") currencySymbol: String, + @PathVariable("currencySymbol") currencySymbol: String ) { walletProxy.deleteGateway(securityContext.jwtAuthentication().tokenValue(), gatewayUuid, currencySymbol) } From 120aad4f05300935c6fb5b82ba9840fe777f2333 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 14:58:55 +0330 Subject: [PATCH 21/56] Update swagger data about currency rate services --- .../opex/controller/CurrencyRatesController.kt | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt index e2a1d698d..8a5aaeb3d 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/CurrencyRatesController.kt @@ -52,9 +52,7 @@ Validation: - `rate` must be greater than zero. - `sourceSymbol` and `destSymbol` must be different. -Request body: SetCurrencyExchangeRateRequest. - -Response body: See schema.""", +Request body: SetCurrencyExchangeRateRequest.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -308,9 +306,7 @@ Required authentication: Validation: - `sourceSymbol` and `destSymbol` must be different. -Request body: CurrencyPair. - -Response body: See schema.""", +Request body: CurrencyPair.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -451,9 +447,7 @@ Required authentication: - Bearer admin-token is required. - Required role: ROLE_admin. -Request body: Symbols. - -Response body: See schema.""", +Request body: Symbols.""", security = [SecurityRequirement(name = "bearerAuth")], requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( required = true, @@ -705,8 +699,6 @@ Route calculation behavior: - If both are omitted, routes are calculated for all possible symbol combinations. - Do not send the literal string "null". Omit the query parameter when it should be treated as null. -Request body: See schema. - Response body: CurrencyExchangeRatesResponse.""", security = [SecurityRequirement(name = "bearerAuth")], parameters = [ From 22d7f2f7074a211e368699c00cff878e7826eaba Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 14:59:55 +0330 Subject: [PATCH 22/56] Update swagger data about deposit admin services --- .../opex/api/ports/opex/controller/DepositAdminController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt index 1a4c07cf7..532d085dd 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt @@ -31,7 +31,7 @@ class DepositAdminController( Security: Bearer admin-token required. Required authority: ROLE_admin.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] From 04925131acdd71e72b121cc274fae6c712c2758f Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 15:03:25 +0330 Subject: [PATCH 23/56] Update swagger data about deposit and gateway services --- .../opex/controller/DepositController.kt | 5 +- .../opex/controller/GatewayAdminController.kt | 461 ++++++++++++++++-- 2 files changed, 424 insertions(+), 42 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt index 831aa83d3..1fe38ab99 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt @@ -26,11 +26,10 @@ class DepositController(private val walletProxy: WalletProxy) { summary = "Deposit", description = """POST /opex/v1/deposit. Security: Bearer user-token required. Required authority: PERM_deposit:write. - -Behavior: Use gatewayUuid/chain when the deposit flow requires a specific gateway or network. The receiver wallet type must be one of the server-supported wallet types.""", +""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_deposit:write. No response body.", content = [Content()]) ] diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt index 7eed711d5..983019b45 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt @@ -1,63 +1,357 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.CurrencyGatewayCommand +import co.nilin.opex.api.core.inout.OffChainGatewayCommand +import co.nilin.opex.api.core.inout.OnChainGatewayCommand import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.parameters.RequestBody as SwaggerRequestBody import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/admin") @Tag(name = "Gateway Admin", description = "Admin gateway management for currencies.") class GatewayAdminController( - private val walletProxy: WalletProxy + private val walletProxy: WalletProxy, ) { + @PostMapping("/{currencySymbol}/gateway") @Operation( - summary = "Add currency to gateway", - description = """POST /opex/v1/admin/{currencySymbol}/gateway. -Security: Bearer admin-token required. Required authority: ROLE_admin. + summary = "Add currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. -Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", +Behavior: +- OffChain gateways use type=OffChain and transferMethod. +- OnChain native gateways use type=OnChain and isToken=false. +- Token gateways use type=OnChain and isToken=true with token fields. + +Source of values: +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- chain values should come from the server-provided chain list. + +Response body: CurrencyGatewayCommand. + """, security = [SecurityRequirement(name = "bearerAuth")], + requestBody = SwaggerRequestBody( + required = true, + description = "CurrencyGatewayCommand. Use one of: OffChainGatewayCommand, OnChainGatewayCommand, or OnChainGatewayCommand with isToken=true for token gateways.", + content = [ + Content( + mediaType = "application/json", + schema = Schema( + oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], + discriminatorProperty = "type" + ), + examples = [ + ExampleObject( + name = "OffChain gateway", + summary = "OffChainGatewayCommand", + value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """ + ), + ExampleObject( + name = "OnChain native gateway", + summary = "OnChainGatewayCommand with isToken=false", + value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """ + ), + ExampleObject( + name = "OnChain token gateway", + summary = "OnChainGatewayCommand with isToken=true", + value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """ + ) + ] + ) + ] + ), responses = [ - ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyGatewayCommand::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Gateway created successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema( + oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], + discriminatorProperty = "type" + ), + examples = [ + ExampleObject(name = "OffChain gateway response", value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """), + ExampleObject(name = "OnChain native gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """), + ExampleObject(name = "OnChain token gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """) + ] + ) + ] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) ] ) suspend fun addCurrencyToGateway( @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currencySymbol") currencySymbol: String, - @RequestBody body: CurrencyGatewayCommand + @RequestBody body: CurrencyGatewayCommand, ): CurrencyGatewayCommand? { return walletProxy.addCurrencyToGateway(securityContext.jwtAuthentication().tokenValue(), currencySymbol, body) } - @PutMapping("/{currencySymbol}/gateway/{uuid}") @Operation( - summary = "Update gateway", - description = """PUT /opex/v1/admin/{currencySymbol}/gateway/{uuid}. -Security: Bearer admin-token required. Required authority: ROLE_admin. + summary = "Update currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. + +Behavior: +- OffChain gateways use type=OffChain and transferMethod. +- OnChain native gateways use type=OnChain and isToken=false. +- Token gateways use type=OnChain and isToken=true with token fields. + +Source of values: +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- chain values should come from the server-provided chain list. -Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", +Response body: CurrencyGatewayCommand. + """, security = [SecurityRequirement(name = "bearerAuth")], + requestBody = SwaggerRequestBody( + required = true, + description = "CurrencyGatewayCommand. Use one of: OffChainGatewayCommand, OnChainGatewayCommand, or OnChainGatewayCommand with isToken=true for token gateways.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"), + examples = [ + ExampleObject(name = "OffChain gateway", summary = "OffChainGatewayCommand", value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """), + ExampleObject(name = "OnChain native gateway", summary = "OnChainGatewayCommand with isToken=false", value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """), + ExampleObject(name = "OnChain token gateway", summary = "OnChainGatewayCommand with isToken=true", value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """) + ] + ) + ] + ), responses = [ - ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyGatewayCommand::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Gateway updated successfully.", + content = [Content(mediaType = "application/json", schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"))] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) ] ) suspend fun updateGateway( @@ -65,7 +359,7 @@ Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, - @RequestBody body: CurrencyGatewayCommand + @RequestBody body: CurrencyGatewayCommand, ): CurrencyGatewayCommand? { return walletProxy.updateGateway( securityContext.jwtAuthentication().tokenValue(), @@ -77,23 +371,110 @@ Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method @GetMapping("/{currencySymbol}/gateway/{uuid}") @Operation( - summary = "Get gateway", - description = """GET /opex/v1/admin/{currencySymbol}/gateway/{uuid}. -Security: Bearer admin-token required. Required authority: ROLE_admin. + summary = "Get currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. -Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", +Behavior: +- Response can be OffChainGatewayCommand, OnChainGatewayCommand, or OnChainGatewayCommand with isToken=true for token gateways. + +Response body: CurrencyGatewayCommand. + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Response body: See schema.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyGatewayCommand::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Gateway returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"), + examples = [ + ExampleObject(name = "OffChain gateway response", value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """), + ExampleObject(name = "OnChain native gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """), + ExampleObject(name = "OnChain token gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """) + ] + ) + ] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) ] ) suspend fun getGateway( @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, - @PathVariable("currencySymbol") currencySymbol: String + @PathVariable("currencySymbol") currencySymbol: String, ): CurrencyGatewayCommand? { return walletProxy.getGateway( securityContext.jwtAuthentication().tokenValue(), @@ -104,25 +485,27 @@ Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method @DeleteMapping("/{currencySymbol}/gateway/{uuid}") @Operation( - summary = "Delete gateway", - description = """DELETE /opex/v1/admin/{currencySymbol}/gateway/{uuid}. -Security: Bearer admin-token required. Required authority: ROLE_admin. + summary = "Delete currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. -Behavior: Gateway fields differ by gateway type. Keep off-chain transfer-method fields and on-chain/token fields consistent with the gateway being created or updated.""", +Response body: No response body. + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse(responseCode = "200", description = "Gateway deleted successfully. No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) ] ) suspend fun deleteGateway( @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, - @PathVariable("currencySymbol") currencySymbol: String + @PathVariable("currencySymbol") currencySymbol: String, ) { walletProxy.deleteGateway(securityContext.jwtAuthentication().tokenValue(), gatewayUuid, currencySymbol) } - } From 69b8584f308e752d60b024b74f0fcb56e9ee4b61 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 15:05:42 +0330 Subject: [PATCH 24/56] Update swagger data about localiztion admin services --- .../controller/LocalizationAdminController.kt | 145 +++++++++++++----- 1 file changed, 104 insertions(+), 41 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt index c13801ee7..bed3def15 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt @@ -6,36 +6,41 @@ import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue import co.nilin.opex.common.OpexError +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/admin") -@Tag(name = "Localization Admin", description = "Admin localization management for currencies, terminals, and gateways") +@Tag(name = "Localization Admin", description = "Admin localization management for currencies, terminals, and gateways.") class LocalizationAdminController( private val walletProxy: WalletProxy, private val blockchainGatewayProxy: BlockchainGatewayProxy ) { @GetMapping("/currency/{currency}/localization") @Operation( - summary = "Admin: get currency localizations", + summary = "Get currency localizations", + description = """GET /opex/v1/admin/currency/{currency}/localization. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "currency", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) - ], - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = CurrencyLocalizationResponse::class)) ]) ] + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyLocalizationResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun getCurrencyLocalizations( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currency") currency: String ): CurrencyLocalizationResponse { @@ -44,13 +49,20 @@ class LocalizationAdminController( @PostMapping("/currency/{currency}/localization") @Operation( - summary = "Admin: save currency localizations", + summary = "Save currency localizations", + description = """POST /opex/v1/admin/currency/{currency}/localization. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ Parameter(name = "currency", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyLocalizationCommand::class))) ]), - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = CurrencyLocalizationResponse::class)) ]) ] + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CurrencyLocalizationResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun saveCurrencyLocalizations( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currency") currency: String, @RequestBody currencyLocalizations: List @@ -64,12 +76,20 @@ class LocalizationAdminController( @DeleteMapping("/currency/localization/{id}") @Operation( - summary = "Admin: delete currency localization", + summary = "Delete currency localization", + description = """DELETE /opex/v1/admin/currency/localization/{id}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) ], - responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun deleteCurrencyLocalization( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("id") id: Long ) { @@ -78,12 +98,20 @@ class LocalizationAdminController( @GetMapping("/terminal/{terminalUuid}/localization") @Operation( - summary = "Admin: get terminal localizations", + summary = "Get terminal localizations", + description = """GET /opex/v1/admin/terminal/{terminalUuid}/localization. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ Parameter(name = "terminalUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = TerminalLocalizationResponse::class)) ]) ] + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalLocalizationResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun getTerminalLocalizations( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("terminalUuid") terminalUuid: String ): TerminalLocalizationResponse { @@ -92,13 +120,20 @@ class LocalizationAdminController( @PostMapping("/terminal/{terminalUuid}/localization") @Operation( - summary = "Admin: save terminal localizations", + summary = "Save terminal localizations", + description = """POST /opex/v1/admin/terminal/{terminalUuid}/localization. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ Parameter(name = "terminalUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = TerminalLocalizationCommand::class))) ]), - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = TerminalLocalizationResponse::class)) ]) ] + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalLocalizationResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun saveTerminalLocalizations( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("terminalUuid") terminalUuid: String, @RequestBody terminalLocalizations: List @@ -112,12 +147,20 @@ class LocalizationAdminController( @DeleteMapping("/terminal/localization/{id}") @Operation( - summary = "Admin: delete terminal localization", + summary = "Delete terminal localization", + description = """DELETE /opex/v1/admin/terminal/localization/{id}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) ], - responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun deleteTerminalLocalization( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("id") id: Long ) { @@ -126,12 +169,20 @@ class LocalizationAdminController( @GetMapping("/gateway/{gatewayUuid}/localization") @Operation( - summary = "Admin: get gateway localization", + summary = "Get gateway localization", + description = """GET /opex/v1/admin/gateway/{gatewayUuid}/localization. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ Parameter(name = "gatewayUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = GatewayLocalizationResponse::class)) ]) ] + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = GatewayLocalizationResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun getGatewayLocalization( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("gatewayUuid") gatewayUuid: String ): GatewayLocalizationResponse { @@ -149,13 +200,20 @@ class LocalizationAdminController( @PostMapping("/gateway/{gatewayUuid}/localization") @Operation( - summary = "Admin: save gateway localizations", + summary = "Save gateway localizations", + description = """POST /opex/v1/admin/gateway/{gatewayUuid}/localization. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ Parameter(name = "gatewayUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) ], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = [ Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = GatewayLocalizationCommand::class))) ]), - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = GatewayLocalizationResponse::class)) ]) ] + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = GatewayLocalizationResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun saveGatewayLocalizations( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("gatewayUuid") gatewayUuid: String, @RequestBody gatewayLocalizations: List @@ -177,15 +235,20 @@ class LocalizationAdminController( @DeleteMapping("/gateway/{gatewayUuid}/localization/{id}") @Operation( - summary = "Admin: delete gateway localization", + summary = "Delete gateway localization", + description = """DELETE /opex/v1/admin/gateway/{gatewayUuid}/localization/{id}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Send one localization object per language. Existing items can include `id`; new items should use null or omit `id`.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "gatewayUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")), - Parameter(name = "id", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "integer", format = "int64")) - ], - responses = [ ApiResponse(responseCode = "200", description = "Deleted") ] + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] ) suspend fun deleteGatewayLocalization( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("id") id: Long, @PathVariable("gatewayUuid") gatewayUuid: String @@ -202,4 +265,4 @@ class LocalizationAdminController( ) } else throw OpexError.GatewayNotFount.exception() } -} \ No newline at end of file +} From 1e15f9a1364f360ff7eaff8dcad8082ab12f44e7 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 12 May 2026 15:12:30 +0330 Subject: [PATCH 25/56] Update swagger data about market services --- .../ports/opex/controller/MarketController.kt | 141 +++++++++++++++++- 1 file changed, 135 insertions(+), 6 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt index 5ea8c718d..2901e18b4 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt @@ -15,9 +15,18 @@ import org.springframework.web.bind.annotation.* import java.math.BigDecimal import java.time.ZoneId import kotlin.collections.mapNotNull +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController("opexMarketController") @RequestMapping("/opex/v1/market") +@Tag(name = "Market", description = "Public market information, order book, trades, tickers, and basic market data.") class MarketController( private val accountantProxy: AccountantProxy, private val marketStatProxy: MarketStatProxy, @@ -26,17 +35,33 @@ class MarketController( private val matchingGatewayProxy: MatchingGatewayProxy, private val blockChainGatewayProxy: BlockchainGatewayProxy, @Value("\${app.user-activity-reference-currency}") - private val userActivityReferenceCurrency: String, + private val userActivityReferenceCurrency: String ) { private val orderBookValidLimits = arrayListOf(5, 10, 20, 50, 100, 500, 1000, 5000) private val validDurations = arrayListOf("24h", "7d", "1M") @GetMapping("/currency") + @Operation( + summary = "Get currencies", + description = """GET /opex/v1/market/currency. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyData::class)))]) + ] + ) suspend fun getCurrencies(): List { return walletProxy.getCurrencies() } @GetMapping("/pair") + @Operation( + summary = "Get pairs", + description = """GET /opex/v1/market/pair. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = PairInfoResponse::class)))]) + ] + ) suspend fun getPairs(): List { val pairSettings = matchingGatewayProxy.getPairSettings().associateBy { it.pair } @@ -56,24 +81,56 @@ class MarketController( } @GetMapping("/chain") + @Operation( + summary = "Get chains", + description = """GET /opex/v1/market/chain. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = ChainInfo::class)))]) + ] + ) suspend fun getChains(): List { - return blockChainGatewayProxy.getChainInfo() + return blockChainGatewayProxy.getChainInfo() } @GetMapping("/currency/gateway") + @Operation( + summary = "Get currency gateways", + description = """GET /opex/v1/market/currency/gateway. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)))]) + ] + ) suspend fun getCurrencyGateways( @RequestParam(defaultValue = "true") includeOffChainGateways: Boolean, - @RequestParam(defaultValue = "true") includeOnChainGateways: Boolean, + @RequestParam(defaultValue = "true") includeOnChainGateways: Boolean ): List { return walletProxy.getGateWays(includeOffChainGateways, includeOnChainGateways) } @GetMapping("/fee") + @Operation( + summary = "Get fee configs", + description = """GET /opex/v1/market/fee. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = FeeConfig::class)))]) + ] + ) suspend fun getFeeConfigs(): List { return accountantProxy.getFeeConfigs() } @GetMapping("/stats") + @Operation( + summary = "Get market stats", + description = """GET /opex/v1/market/stats. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = MarketInfoResponse::class))]) + ] + ) suspend fun getMarketStats( @RequestParam interval: String, @RequestParam(required = false) limit: Int? @@ -111,11 +168,19 @@ class MarketController( return MarketInfoResponse( marketDataProxy.countActiveUsers(intervalEnum), marketDataProxy.countTotalOrders(intervalEnum), - marketDataProxy.countTotalTrades(intervalEnum), + marketDataProxy.countTotalTrades(intervalEnum) ) } @GetMapping("/depth") + @Operation( + summary = "Order book", + description = """GET /opex/v1/market/depth. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = OrderBookResponse::class))]) + ] + ) suspend fun orderBook( @RequestParam symbol: String, @@ -153,6 +218,14 @@ class MarketController( } @GetMapping("/trades") + @Operation( + summary = "Recent trades", + description = """GET /opex/v1/market/trades. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = RecentTradeResponse::class)))]) + ] + ) suspend fun recentTrades( @RequestParam symbol: String, @@ -178,6 +251,14 @@ class MarketController( } @GetMapping("/ticker/{duration:24h|7d|1M}") + @Operation( + summary = "Price change", + description = """GET /opex/v1/market/ticker/{duration:24h|7d|1M}. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = PriceChange::class)))]) + ] + ) suspend fun priceChange( @PathVariable duration: String, @RequestParam(required = false) symbol: String?, @@ -205,16 +286,40 @@ class MarketController( } @GetMapping("/ticker/price") + @Operation( + summary = "Price ticker", + description = """GET /opex/v1/market/ticker/price. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = PriceTicker::class)))]) + ] + ) suspend fun priceTicker(@RequestParam(required = false) symbol: String?): List { return marketDataProxy.lastPrice(symbol) } @GetMapping("/currencyInfo/quotes") + @Operation( + summary = "Get quote currencies", + description = """GET /opex/v1/market/currencyInfo/quotes. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(type = "string")))]) + ] + ) suspend fun getQuoteCurrencies(): List { return walletProxy.getQuoteCurrencies().map { it.currency } } @GetMapping("/klines") + @Operation( + summary = "Klines", + description = """GET /opex/v1/market/klines. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = List::class)))]) + ] + ) suspend fun klines( @RequestParam symbol: String, @@ -257,6 +362,14 @@ class MarketController( } @GetMapping("/basic-data") + @Operation( + summary = "Get basic data", + description = """GET /opex/v1/market/basic-data. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = MarketBasicData::class))]) + ] + ) suspend fun getBasicData(): MarketBasicData { val quoteCurrencies = walletProxy.getQuoteCurrencies() return MarketBasicData( @@ -268,13 +381,29 @@ class MarketController( } @GetMapping("/withdraw-limits") + @Operation( + summary = "Get withdraw limits", + description = """GET /opex/v1/market/withdraw-limits. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WithdrawLimitConfig::class)))]) + ] + ) suspend fun getWithdrawLimits(): List { return accountantProxy.getWithdrawLimitConfigs() } @GetMapping("/gateway/{gatewayUuid}/terminal") + @Operation( + summary = "Get gateway terminal", + description = """GET /opex/v1/market/gateway/{gatewayUuid}/terminal. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)))]) + ] + ) suspend fun getGatewayTerminal( - @PathVariable("gatewayUuid") gatewayUuid: String, + @PathVariable("gatewayUuid") gatewayUuid: String ): List? { return walletProxy.getGatewayTerminal(gatewayUuid) } @@ -285,4 +414,4 @@ class MarketController( limit < 1 -> 1 else -> limit } -} \ No newline at end of file +} From df19f744ad166353ab927f9de45d401354a22f91 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Wed, 13 May 2026 16:26:42 +0330 Subject: [PATCH 26/56] Update swagger data about gateway admin services --- .../co/nilin/opex/api/core/spi/WalletProxy.kt | 2 +- .../opex/controller/GatewayAdminController.kt | 456 +++++++++++++++++- .../ports/opex/controller/MarketController.kt | 154 +++++- .../api/ports/proxy/impl/WalletProxyImpl.kt | 2 +- common/pom.xml | 11 +- .../nilin/opex/common/utils/LanguageUtils.kt | 2 +- pom.xml | 2 +- .../postgres/dao/OffChainGatewayRepository.kt | 79 +-- .../impl/OffChainGatewayManagerImpl.kt | 38 +- 9 files changed, 668 insertions(+), 78 deletions(-) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index 402f8bd21..2983e608a 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -244,7 +244,7 @@ interface WalletProxy { suspend fun getAssignedGatewayToTerminal(token: String, terminalUuid: String): List? suspend fun assignTerminalsToGateway(token: String, gatewayUuid: String, terminal: List) suspend fun revokeTerminalsToGateway(token: String, gatewayUuid: String, terminal: List) - suspend fun addCurrencyToGateway( + suspend fun addGatewayToCurrency( token: String, currencySymbol: String, gatewayCommand: CurrencyGatewayCommand diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt index 85889788f..3022d027b 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt @@ -1,34 +1,365 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.CurrencyGatewayCommand +import co.nilin.opex.api.core.inout.OffChainGatewayCommand +import co.nilin.opex.api.core.inout.OnChainGatewayCommand import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.parameters.RequestBody as SwaggerRequestBody +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/admin") +@Tag(name = "Gateway Admin", description = "Admin gateway management for currencies.") class GatewayAdminController( private val walletProxy: WalletProxy, ) { + @PostMapping("/{currencySymbol}/gateway") + @Operation( + summary = "Add currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. + +Behavior: +- OffChain gateways use type=OffChain and transferMethod. +- OnChain native gateways use type=OnChain and isToken=false. +- Token gateways use type=OnChain and isToken=true with token fields. + +Source of values: +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- chain values should come from the server-provided chain list. + +Response body: CurrencyGatewayCommand. + """, + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = SwaggerRequestBody( + required = true, + description = "CurrencyGatewayCommand. Use one of: OffChainGatewayCommand, OnChainGatewayCommand, or OnChainGatewayCommand with isToken=true for token gateways.", + content = [ + Content( + mediaType = "application/json", + schema = Schema( + oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], + discriminatorProperty = "type" + ), + examples = [ + ExampleObject( + name = "OffChain gateway", + summary = "OffChainGatewayCommand", + value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """ + ), + ExampleObject( + name = "OnChain native gateway", + summary = "OnChainGatewayCommand with isToken=false", + value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """ + ), + ExampleObject( + name = "OnChain token gateway", + summary = "OnChainGatewayCommand with isToken=true", + value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """ + ) + ] + ) + ] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Gateway created successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema( + oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], + discriminatorProperty = "type" + ), + examples = [ + ExampleObject(name = "OffChain gateway response", value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """), + ExampleObject(name = "OnChain native gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """), + ExampleObject(name = "OnChain token gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """) + ] + ) + ] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) + ] + ) suspend fun addGatewayToCurrency( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("currencySymbol") currencySymbol: String, @RequestBody body: CurrencyGatewayCommand, ): CurrencyGatewayCommand? { - return walletProxy.addCurrencyToGateway(securityContext.jwtAuthentication().tokenValue(), currencySymbol, body) + return walletProxy.addGatewayToCurrency(securityContext.jwtAuthentication().tokenValue(), currencySymbol, body) } - @PutMapping("/{currencySymbol}/gateway/{uuid}") + @Operation( + summary = "Update currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. + +Behavior: +- OffChain gateways use type=OffChain and transferMethod. +- OnChain native gateways use type=OnChain and isToken=false. +- Token gateways use type=OnChain and isToken=true with token fields. + +Source of values: +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- chain values should come from the server-provided chain list. + +Response body: CurrencyGatewayCommand. + """, + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = SwaggerRequestBody( + required = true, + description = "CurrencyGatewayCommand. Use one of: OffChainGatewayCommand, OnChainGatewayCommand, or OnChainGatewayCommand with isToken=true for token gateways.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"), + examples = [ + ExampleObject(name = "OffChain gateway", summary = "OffChainGatewayCommand", value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """), + ExampleObject(name = "OnChain native gateway", summary = "OnChainGatewayCommand with isToken=false", value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """), + ExampleObject(name = "OnChain token gateway", summary = "OnChainGatewayCommand with isToken=true", value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """) + ] + ) + ] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Gateway updated successfully.", + content = [Content(mediaType = "application/json", schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"))] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) + ] + ) suspend fun updateGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, - @RequestBody body: CurrencyGatewayCommand + @RequestBody body: CurrencyGatewayCommand, ): CurrencyGatewayCommand? { return walletProxy.updateGateway( securityContext.jwtAuthentication().tokenValue(), @@ -39,7 +370,108 @@ class GatewayAdminController( } @GetMapping("/{currencySymbol}/gateway/{uuid}") + @Operation( + summary = "Get currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. + +Behavior: +- Response can be OffChainGatewayCommand, OnChainGatewayCommand, or OnChainGatewayCommand with isToken=true for token gateways. + +Response body: CurrencyGatewayCommand. + """, + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Gateway returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"), + examples = [ + ExampleObject(name = "OffChain gateway response", value = """ +{ + "type": "OffChain", + "currencySymbol": "IRT", + "gatewayUuid": "ofg-card-irt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 100000, + "depositMax": 500000000, + "withdrawMin": 100000, + "withdrawMax": 500000000, + "depositDescription": "Card deposit", + "withdrawDescription": "Card withdraw", + "displayOrder": 1, + "transferMethod": "CARD" +} + """), + ExampleObject(name = "OnChain native gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "BTC", + "gatewayUuid": "ong-bitcoin-btc", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 0.0005, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 0.0001, + "depositMax": 10, + "withdrawMin": 0.0001, + "withdrawMax": 5, + "depositDescription": "Bitcoin deposit", + "withdrawDescription": "Bitcoin withdraw", + "displayOrder": 1, + "implementationSymbol": "BTC", + "tokenName": null, + "tokenAddress": null, + "isToken": false, + "decimal": 8, + "chain": "bitcoin" +} + """), + ExampleObject(name = "OnChain token gateway response", value = """ +{ + "type": "OnChain", + "currencySymbol": "USDT", + "gatewayUuid": "ong-tron-usdt", + "isDepositActive": true, + "isWithdrawActive": true, + "withdrawFee": 1, + "withdrawAllowed": true, + "depositAllowed": true, + "depositMin": 1, + "depositMax": 100000, + "withdrawMin": 1, + "withdrawMax": 50000, + "depositDescription": "USDT TRC20 deposit", + "withdrawDescription": "USDT TRC20 withdraw", + "displayOrder": 2, + "implementationSymbol": "USDT", + "tokenName": "Tether USD", + "tokenAddress": "TX0000000000000000000000000000000000", + "isToken": true, + "decimal": 6, + "chain": "tron" +} + """) + ] + ) + ] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) + ] + ) suspend fun getGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, @@ -52,12 +484,28 @@ class GatewayAdminController( } @DeleteMapping("/{currencySymbol}/gateway/{uuid}") + @Operation( + summary = "Delete currency gateway", + description = """ +Security: +- Bearer admin-token is required. +- Required authority: ROLE_admin. + +Response body: No response body. + """, + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Gateway deleted successfully. No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) + ] + ) suspend fun deleteGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, ) { walletProxy.deleteGateway(securityContext.jwtAuthentication().tokenValue(), gatewayUuid, currencySymbol) } - } diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt index 2901e18b4..913e1cc1c 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt @@ -8,21 +8,18 @@ import co.nilin.opex.api.ports.opex.data.OrderBookResponse import co.nilin.opex.api.ports.opex.data.RecentTradeResponse import co.nilin.opex.common.OpexError import co.nilin.opex.common.utils.Interval -import kotlinx.coroutines.async -import kotlinx.coroutines.coroutineScope -import org.springframework.beans.factory.annotation.Value -import org.springframework.web.bind.annotation.* -import java.math.BigDecimal -import java.time.ZoneId -import kotlin.collections.mapNotNull import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import org.springframework.beans.factory.annotation.Value +import org.springframework.web.bind.annotation.* +import java.math.BigDecimal +import java.time.ZoneId @RestController("opexMarketController") @RequestMapping("/opex/v1/market") @@ -46,7 +43,14 @@ class MarketController( description = """GET /opex/v1/market/currency. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyData::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = CurrencyData::class)) + )] + ) ] ) suspend fun getCurrencies(): List { @@ -59,7 +63,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/pair. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = PairInfoResponse::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = PairInfoResponse::class)) + )] + ) ] ) suspend fun getPairs(): List { @@ -86,7 +97,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/chain. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = ChainInfo::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = ChainInfo::class)) + )] + ) ] ) suspend fun getChains(): List { @@ -99,7 +117,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/currency/gateway. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)) + )] + ) ] ) suspend fun getCurrencyGateways( @@ -115,7 +140,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/fee. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = FeeConfig::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = FeeConfig::class)) + )] + ) ] ) suspend fun getFeeConfigs(): List { @@ -128,7 +160,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/stats. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = MarketInfoResponse::class))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = MarketInfoResponse::class) + )] + ) ] ) suspend fun getMarketStats( @@ -178,7 +217,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/depth. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = OrderBookResponse::class))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = OrderBookResponse::class) + )] + ) ] ) suspend fun orderBook( @@ -223,7 +269,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/trades. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = RecentTradeResponse::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = RecentTradeResponse::class)) + )] + ) ] ) suspend fun recentTrades( @@ -256,7 +309,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/ticker/{duration:24h|7d|1M}. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = PriceChange::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = PriceChange::class)) + )] + ) ] ) suspend fun priceChange( @@ -291,7 +351,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/ticker/price. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = PriceTicker::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = PriceTicker::class)) + )] + ) ] ) suspend fun priceTicker(@RequestParam(required = false) symbol: String?): List { @@ -304,7 +371,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/currencyInfo/quotes. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(type = "string")))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(type = "string")) + )] + ) ] ) suspend fun getQuoteCurrencies(): List { @@ -317,7 +391,18 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/klines. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = List::class)))]) + ApiResponse( + responseCode = "200", + description = "Returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema( + schema = Schema(type = "array") + ) + ) + ] + ) ] ) suspend fun klines( @@ -367,7 +452,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/basic-data. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = MarketBasicData::class))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = MarketBasicData::class) + )] + ) ] ) suspend fun getBasicData(): MarketBasicData { @@ -386,7 +478,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/withdraw-limits. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WithdrawLimitConfig::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = WithdrawLimitConfig::class)) + )] + ) ] ) suspend fun getWithdrawLimits(): List { @@ -399,7 +498,14 @@ Security: Public endpoint. No Bearer token is required.""", description = """GET /opex/v1/market/gateway/{gatewayUuid}/terminal. Security: Public endpoint. No Bearer token is required.""", responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)) + )] + ) ] ) suspend fun getGatewayTerminal( diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index 25d7b969f..02e82d2cb 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -1047,7 +1047,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC .awaitBodilessEntity() } - override suspend fun addCurrencyToGateway( + override suspend fun addGatewayToCurrency( token: String, currencySymbol: String, gatewayCommand: CurrencyGatewayCommand diff --git a/common/pom.xml b/common/pom.xml index 16ba962a2..b251e624a 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -14,7 +14,7 @@ jar common Common codes and logic - 1.0.1-beta.36 + 1.0.1-beta.37 @@ -29,6 +29,10 @@ co.nilin.opex.utility error-handler + + co.nilin.opex.utility + interceptors + org.springframework.boot spring-boot-starter-oauth2-resource-server @@ -50,6 +54,11 @@ error-handler ${error-hanlder.version} + + co.nilin.opex.utility + interceptors + ${interceptor.version} + diff --git a/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt b/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt index 9c04ab8db..fc2a0a0c5 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/utils/LanguageUtils.kt @@ -10,7 +10,7 @@ object LanguageUtils { Mono.deferContextual { ctx -> Mono.just(ctx.getOrDefault("lang", getDefaultUserLanguage())!!) } fun getDefaultUserLanguage(): String { - return try { + return try { GlobalWebConfigCache.webConfig?.defaultLanguage?.toString() ?: UserLanguage.EN.toString() } catch (e: Exception) { UserLanguage.EN.toString() diff --git a/pom.xml b/pom.xml index e7514e336..b5af9c400 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ 1.2.23 1.0.8 true - 1.0.1-beta.36 + 1.0.1-beta.37 diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt index b28413a4e..699c5b7d6 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt @@ -15,51 +15,58 @@ interface OffChainGatewayRepository : ReactiveCrudRepository? @Query(""" - select g.id, - g.gateway_uuid, - g.currency_symbol, - g.deposit_allowed, - g.withdraw_fee, - g.withdraw_min, - g.withdraw_max, - g.deposit_min, - g.deposit_max, - g.transfer_method, - g.is_deposit_active, - g.is_withdraw_active, - gl.deposit_description, - gl.withdraw_description, - g.display_order + select g.id as id, + g.gateway_uuid as gatewayUuid, + g.currency_symbol as currencySymbol, + g.withdraw_allowed as withdrawAllowed, + g.deposit_allowed as depositAllowed, + g.withdraw_fee as withdrawFee, + g.withdraw_min as withdrawMin, + g.withdraw_max as withdrawMax, + g.deposit_min as depositMin, + g.deposit_max as depositMax, + g.transfer_method as transferMethod, + g.is_deposit_active as isDepositActive, + g.is_withdraw_active as isWithdrawActive, + gl.deposit_description as depositDescription, + gl.withdraw_description as withdrawDescription, + g.display_order as displayOrder from currency_off_chain_gateway g - left join currency_off_chain_gateway_localization gl on g.id = gl.gateway_id and gl.language = :lang - where g.currency_symbol = :currencySymbol and g.gateway_uuid = :gatewayUuid + left join currency_off_chain_gateway_localization gl + on g.id = gl.gateway_id + and gl.language = :lang + where g.currency_symbol = :currencySymbol + and g.gateway_uuid = :gatewayUuid """) fun findByGatewayUuidAndCurrencySymbol( - uuid: String, - symbol: String, - language: String? = UserLanguage.getDefaultLanguage() + gatewayUuid: String, + currencySymbol: String, + lang: String? = UserLanguage.getDefaultLanguage() ): Mono? fun deleteByGatewayUuid(uuid: String): Mono @Query(""" - select g.id, - g.gateway_uuid, - g.currency_symbol, - g.deposit_allowed, - g.withdraw_fee, - g.withdraw_min, - g.withdraw_max, - g.deposit_min, - g.deposit_max, - g.transfer_method, - g.is_deposit_active, - g.is_withdraw_active, - gl.deposit_description, - gl.withdraw_description, - g.display_order + select g.id as id, + g.gateway_uuid as gatewayUuid, + g.currency_symbol as currencySymbol, + g.withdraw_allowed as withdrawAllowed, + g.deposit_allowed as depositAllowed, + g.withdraw_fee as withdrawFee, + g.withdraw_min as withdrawMin, + g.withdraw_max as withdrawMax, + g.deposit_min as depositMin, + g.deposit_max as depositMax, + g.transfer_method as transferMethod, + g.is_deposit_active as isDepositActive, + g.is_withdraw_active as isWithdrawActive, + gl.deposit_description as depositDescription, + gl.withdraw_description as withdrawDescription, + g.display_order as displayOrder from currency_off_chain_gateway g - left join currency_off_chain_gateway_localization gl on g.id = gl.gateway_id and gl.language = :lang + left join currency_off_chain_gateway_localization gl + on g.id = gl.gateway_id + and gl.language = :language where (:currencySymbol is null or g.currency_symbol = :currencySymbol) and (:gatewayUuid is null or g.gateway_uuid = :gatewayUuid) order by g.display_order diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt index 76e78d67f..69514a064 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt @@ -16,11 +16,15 @@ import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayLocalizationMode import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayModel import co.nilin.opex.wallet.ports.postgres.util.toDto import co.nilin.opex.wallet.ports.postgres.util.toModel +import kotlinx.coroutines.delay import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactor.awaitSingle import kotlinx.coroutines.reactor.awaitSingleOrNull +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import org.springframework.transaction.reactive.TransactionalOperator import org.springframework.transaction.reactive.executeAndAwait +import java.lang.Thread.sleep @Service("offChainGateway") class OffChainGatewayManagerImpl( @@ -28,6 +32,8 @@ class OffChainGatewayManagerImpl( private val offChainGatewayLocalizationRepository: OffChainGatewayLocalizationRepository, private val transactionalOperator: TransactionalOperator ) : GatewayPersister { + private val logger = LoggerFactory.getLogger(OffChainGatewayManagerImpl::class.java) + override suspend fun createGateway( currencyGateway: CurrencyGatewayCommand, internalToken: String? ): CurrencyGatewayCommand? { @@ -78,21 +84,22 @@ class OffChainGatewayManagerImpl( return transactionalOperator.executeAndAwait { val input = currencyGateway as OffChainGatewayCommand - val gateway = offChainGatewayRepository.save(input.toModel()).awaitFirstOrNull() + val gateway = offChainGatewayRepository.save(input.toModel()).awaitSingle() ?: throw OpexError.BadRequest.exception("Error in saving gateway") - - if (!currencyGateway.depositDescription.isNullOrEmpty() && !currencyGateway.withdrawDescription.isNullOrEmpty()) { + var lang: String? = null + if (!currencyGateway.depositDescription.isNullOrEmpty() || !currencyGateway.withdrawDescription.isNullOrEmpty()) { + lang = getDefaultUserLanguage() offChainGatewayLocalizationRepository.save( OffChainGatewayLocalizationModel( gatewayId = gateway.id!!, depositDescription = currencyGateway.depositDescription, withdrawDescription = currencyGateway.withdrawDescription, - language = getDefaultUserLanguage() + language = lang ) - ).awaitSingleOrNull() + ).awaitSingle() } - - _fetchGateway(gateway.currencySymbol, gateway.gatewayUuid) + val savedGateway = _fetchGateway(gateway.currencySymbol, gateway.gatewayUuid, lang) + savedGateway } } @@ -108,9 +115,22 @@ class OffChainGatewayManagerImpl( gatewayUuid: String, language: String? = null, ): OffChainGatewayView? { - return offChainGatewayRepository.findByGatewayUuidAndCurrencySymbol( - gatewayUuid, currencySymbol, language ?: getDefaultUserLanguage() + val resolvedLanguage = language ?: getDefaultUserLanguage() + + logger.info( + "FETCH_GATEWAY_START currencySymbol=$currencySymbol, gatewayUuid=$gatewayUuid, language=$resolvedLanguage" + ) + val result = offChainGatewayRepository.findByGatewayUuidAndCurrencySymbol( + gatewayUuid.trim(), + currencySymbol.trim(), + resolvedLanguage.trim() )?.awaitFirstOrNull() + + logger.info( + "FETCH_GATEWAY_END found=${result != null}, result=$result" + ) + + return result } private suspend fun _fetchGateways( From ef8bd103904cd5714c684e654e7a9734a06df6d1 Mon Sep 17 00:00:00 2001 From: Amir Rajabi <34955519+AmirRajabii@users.noreply.github.com> Date: Wed, 13 May 2026 16:57:24 +0330 Subject: [PATCH 27/56] Enable custom user language and fix localizations (#673) --- .../src/main/resources/application.yml | 2 + .../src/main/resources/application.yml | 2 + .../src/main/resources/application.yml | 2 + .../src/main/resources/application-otc.yml | 2 + .../src/main/resources/application.yml | 2 + .../postgres/impl/CurrencyHandlerImplV2.kt | 2 +- .../opex/common/proxy/CustomMessageClient.kt | 12 +-- ...gClient.kt => CustomUserLanguageClient.kt} | 7 +- .../common/service/WebConfigCacheService.kt | 6 +- .../co/nilin/opex/common/utils/ProxyUtils.kt | 5 ++ .../src/main/resources/application.yml | 7 +- docker-compose-otc.yml | 2 + docker-compose.yml | 36 +++++++++ .../src/main/resources/application.yml | 2 + .../src/main/resources/application.yml | 2 + .../src/main/resources/application.yml | 2 + .../src/main/resources/application.yml | 2 + .../src/main/resources/application.yml | 2 + .../src/main/resources/application-otc.yml | 2 + .../src/main/resources/application.yml | 2 + .../postgres/dao/OffChainGatewayRepository.kt | 75 +++++++++---------- .../impl/OffChainGatewayManagerImpl.kt | 36 ++------- 22 files changed, 130 insertions(+), 82 deletions(-) rename common/src/main/kotlin/co/nilin/opex/common/proxy/{ConfigClient.kt => CustomUserLanguageClient.kt} (72%) create mode 100644 common/src/main/kotlin/co/nilin/opex/common/utils/ProxyUtils.kt diff --git a/accountant/accountant-app/src/main/resources/application.yml b/accountant/accountant-app/src/main/resources/application.yml index d4a8b64f2..1f08d8860 100644 --- a/accountant/accountant-app/src/main/resources/application.yml +++ b/accountant/accountant-app/src/main/resources/application.yml @@ -112,6 +112,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} # --- Swagger / SpringDoc (env-driven) --- diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 9877af2ff..bba9e1cce 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -144,6 +144,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} api: crypto: key: ${api_crypto_key:0e1fd29572ec8c85970d76e3433e96ee} diff --git a/auth-gateway/auth-gateway-app/src/main/resources/application.yml b/auth-gateway/auth-gateway-app/src/main/resources/application.yml index 27413cfdf..5b1550467 100644 --- a/auth-gateway/auth-gateway-app/src/main/resources/application.yml +++ b/auth-gateway/auth-gateway-app/src/main/resources/application.yml @@ -77,6 +77,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} pre-auth-client-secret: ${PRE_AUTH_CLIENT_SECRET} diff --git a/bc-gateway/bc-gateway-app/src/main/resources/application-otc.yml b/bc-gateway/bc-gateway-app/src/main/resources/application-otc.yml index a0d9063bc..cfada5e5f 100644 --- a/bc-gateway/bc-gateway-app/src/main/resources/application-otc.yml +++ b/bc-gateway/bc-gateway-app/src/main/resources/application-otc.yml @@ -93,3 +93,5 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} \ No newline at end of file diff --git a/bc-gateway/bc-gateway-app/src/main/resources/application.yml b/bc-gateway/bc-gateway-app/src/main/resources/application.yml index a8eb6cc2f..1071efc90 100644 --- a/bc-gateway/bc-gateway-app/src/main/resources/application.yml +++ b/bc-gateway/bc-gateway-app/src/main/resources/application.yml @@ -126,6 +126,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} swagger: authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token} diff --git a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt index 489846882..74c781798 100644 --- a/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt +++ b/bc-gateway/bc-gateway-ports/bc-gateway-persister-postgres/src/main/kotlin/co/nilin/opex/bcgateway/ports/postgres/impl/CurrencyHandlerImplV2.kt @@ -121,7 +121,7 @@ class CurrencyHandlerImplV2( return@executeAndAwait null } - if (!request.depositDescription.isNullOrEmpty() && !request.withdrawDescription.isNullOrEmpty()) { + if (!request.depositDescription.isNullOrEmpty() || !request.withdrawDescription.isNullOrEmpty()) { currencyOnChainGatewayLocalizationRepository.save( CurrencyOnChainGatewayLocalizationModel( gatewayId = gateway.id!!, diff --git a/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomMessageClient.kt b/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomMessageClient.kt index 089d6291d..178c1da8b 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomMessageClient.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomMessageClient.kt @@ -2,18 +2,18 @@ package co.nilin.opex.common.proxy import co.nilin.opex.common.config.CommonWebClient import co.nilin.opex.common.data.MessageTranslation +import co.nilin.opex.common.utils.typeRef import kotlinx.coroutines.reactive.awaitFirst import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty -import org.springframework.core.ParameterizedTypeReference import org.springframework.stereotype.Component @Component @ConditionalOnProperty(name = ["app.custom-message.enabled"], havingValue = "true", matchIfMissing = false) class CustomMessageClient( - @Qualifier("CommonWebClient") private val webClient: CommonWebClient + @Qualifier("CommonWebClient") private val webClient: CommonWebClient ) { @Value("\${app.custom-message.base-url}") private lateinit var customMessageBaseUrl: String @@ -22,9 +22,9 @@ class CustomMessageClient( it.queryParam("last-update", lastUpdate) it.build() }.retrieve() - .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToMono(typeRef>()) - .log() - .awaitFirst() + .onStatus({ t -> t.isError }, { it.createException() }) + .bodyToMono(typeRef>()) + .log() + .awaitFirst() } } diff --git a/common/src/main/kotlin/co/nilin/opex/common/proxy/ConfigClient.kt b/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomUserLanguageClient.kt similarity index 72% rename from common/src/main/kotlin/co/nilin/opex/common/proxy/ConfigClient.kt rename to common/src/main/kotlin/co/nilin/opex/common/proxy/CustomUserLanguageClient.kt index 6a28796e5..4aec686f2 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/proxy/ConfigClient.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/proxy/CustomUserLanguageClient.kt @@ -2,15 +2,16 @@ package co.nilin.opex.common.proxy import co.nilin.opex.common.config.CommonWebClient import co.nilin.opex.common.data.WebConfig +import co.nilin.opex.common.utils.typeRef import kotlinx.coroutines.reactive.awaitFirst import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.core.ParameterizedTypeReference +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.stereotype.Component -inline fun typeRef(): ParameterizedTypeReference = object : ParameterizedTypeReference() {} @Component -class ConfigClient( +@ConditionalOnProperty(name = ["app.custom-user-language.enabled"], havingValue = "true", matchIfMissing = false) +class CustomUserLanguageClient( @Qualifier("CommonWebClient") private val webClient: CommonWebClient ) { diff --git a/common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt b/common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt index 89a7e8ee8..b27a9f1f8 100644 --- a/common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt +++ b/common/src/main/kotlin/co/nilin/opex/common/service/WebConfigCacheService.kt @@ -1,8 +1,9 @@ package co.nilin.opex.common.service import co.nilin.opex.common.data.WebConfig -import co.nilin.opex.common.proxy.ConfigClient +import co.nilin.opex.common.proxy.CustomUserLanguageClient import kotlinx.coroutines.runBlocking +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Service @@ -11,9 +12,10 @@ object GlobalWebConfigCache { var webConfig: WebConfig? = null } +@ConditionalOnProperty(name = ["app.custom-user-language.enabled"], havingValue = "true", matchIfMissing = false) @Service class WebConfigService( - private val configClient: ConfigClient, + private val configClient: CustomUserLanguageClient, ) { @Scheduled(fixedDelay = 5 * 60 * 1000) diff --git a/common/src/main/kotlin/co/nilin/opex/common/utils/ProxyUtils.kt b/common/src/main/kotlin/co/nilin/opex/common/utils/ProxyUtils.kt new file mode 100644 index 000000000..d8460685a --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/utils/ProxyUtils.kt @@ -0,0 +1,5 @@ +package co.nilin.opex.common.utils + +import org.springframework.core.ParameterizedTypeReference + +inline fun typeRef(): ParameterizedTypeReference = object : ParameterizedTypeReference() {} diff --git a/device-management/device-management-app/src/main/resources/application.yml b/device-management/device-management-app/src/main/resources/application.yml index 762d30f75..922caeb87 100644 --- a/device-management/device-management-app/src/main/resources/application.yml +++ b/device-management/device-management-app/src/main/resources/application.yml @@ -108,4 +108,9 @@ app: url: lb://opex-auth cert-url: http://keycloak:8080/realms/opex/protocol/openid-connect/certs client-id: none - client-secret: none \ No newline at end of file + client-secret: none + custom-message: + enabled: ${CUSTOM_MESSAGE_ENABLED:false} + base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} \ No newline at end of file diff --git a/docker-compose-otc.yml b/docker-compose-otc.yml index 296198477..3bf37981c 100644 --- a/docker-compose-otc.yml +++ b/docker-compose-otc.yml @@ -38,6 +38,7 @@ services: - AUTH_JWK_ENDPOINT=${JWK_ENDPOINT} - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} extra_hosts: - "host.docker.internal:host-gateway" depends_on: @@ -99,6 +100,7 @@ services: - OMNI_URL=${OMNI_URL} - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} extra_hosts: - "host.docker.internal:host-gateway" depends_on: diff --git a/docker-compose.yml b/docker-compose.yml index 5c8276f04..1bfa5b004 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -266,6 +266,9 @@ services: - SWAGGER_AUTH_URL=$KEYCLOAK_FRONTEND_URL - TRADE_VOLUME_CALCULATION_CURRENCY=${TRADE_VOLUME_CALCULATION_CURRENCY} - WITHDRAW_VOLUME_CALCULATION_CURRENCY=${WITHDRAW_VOLUME_CALCULATION_CURRENCY} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} networks: - default depends_on: @@ -310,6 +313,9 @@ services: - KAFKA_IP_PORT=kafka-1:29092,kafka-2:29092,kafka-3:29092 - REDIS_HOST=redis - SYMBOLS=BTC_USDT,ETH_USDT,BTC_IRT,ETH_IRT,USDT_IRT,ETH_BUSD,BTC_BUSD,BNB_BUSD + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} networks: - default depends_on: @@ -329,6 +335,9 @@ services: - KAFKA_IP_PORT=kafka-1:29092,kafka-2:29092,kafka-3:29092 - REDIS_HOST=redis-duo - SYMBOLS=SOL_USDT,DOGE_USDT,TON_USDT + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} networks: - default depends_on: @@ -352,6 +361,9 @@ services: - VAULT_HOST=vault - SYMBOLS=BTC_USDT,ETH_USDT,BTC_IRT,ETH_IRT,USDT_IRT,ETH_BUSD,BTC_BUSD,BNB_BUSD - TOKEN_ISSUER_URL=${KC_ISSUER_URL} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} networks: - default depends_on: @@ -407,6 +419,9 @@ services: - PRE_AUTH_CLIENT_SECRET=${KC_PRE_AUTH_CLIENT_SECRET} - TOKEN_ISSUER_URL=${KC_ISSUER_URL} - CAPTCHA_ENABLED=${CAPTCHA_ENABLED} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} volumes: - auth-gateway-keys:/app/keys depends_on: @@ -438,6 +453,9 @@ services: - WITHDRAW_BANK_ACCOUNT_VALIDATION=${WITHDRAW_BANK_ACCOUNT_VALIDATION} - TOTAL_ASSET_CALCULATION_CURRENCY=${TOTAL_ASSET_CALCULATION_CURRENCY} - TOKEN_ISSUER_URL=${KC_ISSUER_URL} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} depends_on: - kafka-1 - kafka-2 @@ -463,6 +481,9 @@ services: - VAULT_HOST=vault - SWAGGER_AUTH_URL=$KEYCLOAK_FRONTEND_URL - TOKEN_ISSUER_URL=${KC_ISSUER_URL} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} depends_on: - kafka-1 - kafka-2 @@ -493,6 +514,9 @@ services: - TOTAL_ASSET_CALCULATION_CURRENCY=${TOTAL_ASSET_CALCULATION_CURRENCY} - TOKEN_ISSUER_URL=${KC_ISSUER_URL} - APP_BASE_URL=${APP_BASE_URL} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} - SWAGGER_API_DOCS_ENABLED=${SWAGGER_API_DOCS_ENABLED} - SWAGGER_UI_ENABLED=${SWAGGER_UI_ENABLED} - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} @@ -520,6 +544,9 @@ services: - SWAGGER_AUTH_URL=$KEYCLOAK_FRONTEND_URL - ADDRESS_EXP_TIME=100 - TOKEN_ISSUER_URL=${KC_ISSUER_URL} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} depends_on: - kafka-1 - kafka-2 @@ -555,6 +582,9 @@ services: - SMTP_PROXY_ENABLED=${SMTP_PROXY_ENABLED} - TOKEN_ISSUER_URL=${KC_ISSUER_URL} - OTP_CODE_RESPONSE_ENABLED=${OTP_CODE_RESPONSE_ENABLED} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} depends_on: - consul - postgres-otp @@ -583,6 +613,9 @@ services: - TOKEN_ISSUER_URL=${KC_ISSUER_URL} - MOBILE_IDENTITY_INQUIRY=${MOBILE_IDENTITY_INQUIRY} - PERSONAL_IDENTITY_INQUIRY=${PERSONAL_IDENTITY_INQUIRY} + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} depends_on: - kafka-1 - kafka-2 @@ -607,6 +640,9 @@ services: - BACKEND_USER=${BACKEND_USER} - VAULT_HOST=vault - SWAGGER_AUTH_URL=$KEYCLOAK_FRONTEND_URL + - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} + - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} + - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} depends_on: - kafka-1 - kafka-2 diff --git a/market/market-app/src/main/resources/application.yml b/market/market-app/src/main/resources/application.yml index 42f5d3622..1a8bda75e 100644 --- a/market/market-app/src/main/resources/application.yml +++ b/market/market-app/src/main/resources/application.yml @@ -96,5 +96,7 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} swagger: authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token} diff --git a/matching-engine/matching-engine-app/src/main/resources/application.yml b/matching-engine/matching-engine-app/src/main/resources/application.yml index 45eced541..2e1778e5c 100644 --- a/matching-engine/matching-engine-app/src/main/resources/application.yml +++ b/matching-engine/matching-engine-app/src/main/resources/application.yml @@ -29,3 +29,5 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} diff --git a/matching-gateway/matching-gateway-app/src/main/resources/application.yml b/matching-gateway/matching-gateway-app/src/main/resources/application.yml index 0e75bcc66..694ddba54 100644 --- a/matching-gateway/matching-gateway-app/src/main/resources/application.yml +++ b/matching-gateway/matching-gateway-app/src/main/resources/application.yml @@ -97,6 +97,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} swagger: authUrl: ${SWAGGER_AUTH_URL:https://api.opex.dev/auth}/realms/opex/protocol/openid-connect/token} diff --git a/otp/otp-app/src/main/resources/application.yml b/otp/otp-app/src/main/resources/application.yml index b9109cfad..938ee736f 100644 --- a/otp/otp-app/src/main/resources/application.yml +++ b/otp/otp-app/src/main/resources/application.yml @@ -67,3 +67,5 @@ otp: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} \ No newline at end of file diff --git a/profile/profile-app/src/main/resources/application.yml b/profile/profile-app/src/main/resources/application.yml index f4b00c7ab..bdcdb5251 100644 --- a/profile/profile-app/src/main/resources/application.yml +++ b/profile/profile-app/src/main/resources/application.yml @@ -71,6 +71,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} management: endpoints: diff --git a/wallet/wallet-app/src/main/resources/application-otc.yml b/wallet/wallet-app/src/main/resources/application-otc.yml index ffd08c5c9..897c91f95 100644 --- a/wallet/wallet-app/src/main/resources/application-otc.yml +++ b/wallet/wallet-app/src/main/resources/application-otc.yml @@ -121,6 +121,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} logging: level: root: INFO diff --git a/wallet/wallet-app/src/main/resources/application.yml b/wallet/wallet-app/src/main/resources/application.yml index 8c4c6c27a..488d21278 100644 --- a/wallet/wallet-app/src/main/resources/application.yml +++ b/wallet/wallet-app/src/main/resources/application.yml @@ -165,6 +165,8 @@ app: custom-message: enabled: ${CUSTOM_MESSAGE_ENABLED:false} base-url: ${CUSTOM_MESSAGE_URL} + custom-user-language: + enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} logging: level: root: INFO diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt index 699c5b7d6..8df546227 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/dao/OffChainGatewayRepository.kt @@ -15,58 +15,51 @@ interface OffChainGatewayRepository : ReactiveCrudRepository? @Query(""" - select g.id as id, - g.gateway_uuid as gatewayUuid, - g.currency_symbol as currencySymbol, - g.withdraw_allowed as withdrawAllowed, - g.deposit_allowed as depositAllowed, - g.withdraw_fee as withdrawFee, - g.withdraw_min as withdrawMin, - g.withdraw_max as withdrawMax, - g.deposit_min as depositMin, - g.deposit_max as depositMax, - g.transfer_method as transferMethod, - g.is_deposit_active as isDepositActive, - g.is_withdraw_active as isWithdrawActive, - gl.deposit_description as depositDescription, - gl.withdraw_description as withdrawDescription, - g.display_order as displayOrder + select g.id, + g.gateway_uuid, + g.currency_symbol, + g.deposit_allowed, + g.withdraw_fee, + g.withdraw_min, + g.withdraw_max, + g.deposit_min, + g.deposit_max, + g.transfer_method, + g.is_deposit_active, + g.is_withdraw_active, + gl.deposit_description, + gl.withdraw_description, + g.display_order from currency_off_chain_gateway g - left join currency_off_chain_gateway_localization gl - on g.id = gl.gateway_id - and gl.language = :lang - where g.currency_symbol = :currencySymbol - and g.gateway_uuid = :gatewayUuid + left join currency_off_chain_gateway_localization gl on g.id = gl.gateway_id and gl.language = :language + where g.currency_symbol = :currencySymbol and g.gateway_uuid = :gatewayUuid """) fun findByGatewayUuidAndCurrencySymbol( gatewayUuid: String, currencySymbol: String, - lang: String? = UserLanguage.getDefaultLanguage() + language: String? = UserLanguage.getDefaultLanguage() ): Mono? fun deleteByGatewayUuid(uuid: String): Mono @Query(""" - select g.id as id, - g.gateway_uuid as gatewayUuid, - g.currency_symbol as currencySymbol, - g.withdraw_allowed as withdrawAllowed, - g.deposit_allowed as depositAllowed, - g.withdraw_fee as withdrawFee, - g.withdraw_min as withdrawMin, - g.withdraw_max as withdrawMax, - g.deposit_min as depositMin, - g.deposit_max as depositMax, - g.transfer_method as transferMethod, - g.is_deposit_active as isDepositActive, - g.is_withdraw_active as isWithdrawActive, - gl.deposit_description as depositDescription, - gl.withdraw_description as withdrawDescription, - g.display_order as displayOrder + select g.id, + g.gateway_uuid, + g.currency_symbol, + g.deposit_allowed, + g.withdraw_fee, + g.withdraw_min, + g.withdraw_max, + g.deposit_min, + g.deposit_max, + g.transfer_method, + g.is_deposit_active, + g.is_withdraw_active, + gl.deposit_description, + gl.withdraw_description, + g.display_order from currency_off_chain_gateway g - left join currency_off_chain_gateway_localization gl - on g.id = gl.gateway_id - and gl.language = :language + left join currency_off_chain_gateway_localization gl on g.id = gl.gateway_id and gl.language = :lang where (:currencySymbol is null or g.currency_symbol = :currencySymbol) and (:gatewayUuid is null or g.gateway_uuid = :gatewayUuid) order by g.display_order diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt index 69514a064..cede1053e 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/OffChainGatewayManagerImpl.kt @@ -16,15 +16,11 @@ import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayLocalizationMode import co.nilin.opex.wallet.ports.postgres.model.OffChainGatewayModel import co.nilin.opex.wallet.ports.postgres.util.toDto import co.nilin.opex.wallet.ports.postgres.util.toModel -import kotlinx.coroutines.delay import kotlinx.coroutines.reactive.awaitFirstOrNull -import kotlinx.coroutines.reactor.awaitSingle import kotlinx.coroutines.reactor.awaitSingleOrNull -import org.slf4j.LoggerFactory import org.springframework.stereotype.Service import org.springframework.transaction.reactive.TransactionalOperator import org.springframework.transaction.reactive.executeAndAwait -import java.lang.Thread.sleep @Service("offChainGateway") class OffChainGatewayManagerImpl( @@ -32,8 +28,6 @@ class OffChainGatewayManagerImpl( private val offChainGatewayLocalizationRepository: OffChainGatewayLocalizationRepository, private val transactionalOperator: TransactionalOperator ) : GatewayPersister { - private val logger = LoggerFactory.getLogger(OffChainGatewayManagerImpl::class.java) - override suspend fun createGateway( currencyGateway: CurrencyGatewayCommand, internalToken: String? ): CurrencyGatewayCommand? { @@ -84,22 +78,21 @@ class OffChainGatewayManagerImpl( return transactionalOperator.executeAndAwait { val input = currencyGateway as OffChainGatewayCommand - val gateway = offChainGatewayRepository.save(input.toModel()).awaitSingle() + val gateway = offChainGatewayRepository.save(input.toModel()).awaitFirstOrNull() ?: throw OpexError.BadRequest.exception("Error in saving gateway") - var lang: String? = null + if (!currencyGateway.depositDescription.isNullOrEmpty() || !currencyGateway.withdrawDescription.isNullOrEmpty()) { - lang = getDefaultUserLanguage() offChainGatewayLocalizationRepository.save( OffChainGatewayLocalizationModel( gatewayId = gateway.id!!, depositDescription = currencyGateway.depositDescription, withdrawDescription = currencyGateway.withdrawDescription, - language = lang + language = getDefaultUserLanguage() ) - ).awaitSingle() + ).awaitSingleOrNull() } - val savedGateway = _fetchGateway(gateway.currencySymbol, gateway.gatewayUuid, lang) - savedGateway + + _fetchGateway(gateway.currencySymbol, gateway.gatewayUuid) } } @@ -115,22 +108,9 @@ class OffChainGatewayManagerImpl( gatewayUuid: String, language: String? = null, ): OffChainGatewayView? { - val resolvedLanguage = language ?: getDefaultUserLanguage() - - logger.info( - "FETCH_GATEWAY_START currencySymbol=$currencySymbol, gatewayUuid=$gatewayUuid, language=$resolvedLanguage" - ) - val result = offChainGatewayRepository.findByGatewayUuidAndCurrencySymbol( - gatewayUuid.trim(), - currencySymbol.trim(), - resolvedLanguage.trim() + return offChainGatewayRepository.findByGatewayUuidAndCurrencySymbol( + gatewayUuid, currencySymbol, language ?: getDefaultUserLanguage() )?.awaitFirstOrNull() - - logger.info( - "FETCH_GATEWAY_END found=${result != null}, result=$result" - ) - - return result } private suspend fun _fetchGateways( From 95f0d3eee783f00f5763959ed37363543fceb768 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sat, 16 May 2026 19:03:08 +0330 Subject: [PATCH 28/56] Remove deposit service from api --- .../co/nilin/opex/api/core/spi/WalletProxy.kt | 3 -- .../opex/controller/DepositController.kt | 40 ------------------- .../controller/LocalizationAdminController.kt | 6 +-- .../api/ports/proxy/impl/WalletProxyImpl.kt | 20 ---------- .../opex/wallet/app/service/DepositService.kt | 2 +- 5 files changed, 4 insertions(+), 67 deletions(-) delete mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index 2983e608a..2614594fd 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -104,9 +104,6 @@ interface WalletProxy { limit: Int?, ): List - suspend fun deposit( - request: RequestDepositBody - ): TransferResult? suspend fun requestWithdraw( token: String, diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt deleted file mode 100644 index 1fe38ab99..000000000 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositController.kt +++ /dev/null @@ -1,40 +0,0 @@ -package co.nilin.opex.api.ports.opex.controller - -import co.nilin.opex.api.core.inout.RequestDepositBody -import co.nilin.opex.api.core.inout.TransferResult -import co.nilin.opex.api.core.spi.WalletProxy -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController -import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.media.ArraySchema -import io.swagger.v3.oas.annotations.media.Content -import io.swagger.v3.oas.annotations.media.Schema -import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.security.SecurityRequirement -import io.swagger.v3.oas.annotations.tags.Tag - -@RestController -@RequestMapping("/opex/v1/deposit") -@Tag(name = "Deposit", description = "Authenticated deposit operations.") -class DepositController(private val walletProxy: WalletProxy) { - - @PostMapping - @Operation( - summary = "Deposit", - description = """POST /opex/v1/deposit. -Security: Bearer user-token required. Required authority: PERM_deposit:write. -""", - security = [SecurityRequirement(name = "bearerAuth")], - responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_deposit:write. No response body.", content = [Content()]) - ] - ) - suspend fun deposit(@RequestBody request: RequestDepositBody): TransferResult? { - return walletProxy.deposit(request) - } -} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt index bed3def15..e84ced5fc 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/LocalizationAdminController.kt @@ -49,7 +49,7 @@ Behavior: Send one localization object per language. Existing items can include @PostMapping("/currency/{currency}/localization") @Operation( - summary = "Save currency localizations", + summary = "Save or update currency localizations", description = """POST /opex/v1/admin/currency/{currency}/localization. Security: Bearer admin-token required. Required authority: ROLE_admin. @@ -120,7 +120,7 @@ Behavior: Send one localization object per language. Existing items can include @PostMapping("/terminal/{terminalUuid}/localization") @Operation( - summary = "Save terminal localizations", + summary = "Save or update terminal localizations", description = """POST /opex/v1/admin/terminal/{terminalUuid}/localization. Security: Bearer admin-token required. Required authority: ROLE_admin. @@ -200,7 +200,7 @@ Behavior: Send one localization object per language. Existing items can include @PostMapping("/gateway/{gatewayUuid}/localization") @Operation( - summary = "Save gateway localizations", + summary = "Save or update gateway localizations", description = """POST /opex/v1/admin/gateway/{gatewayUuid}/localization. Security: Bearer admin-token required. Required authority: ROLE_admin. diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index 02e82d2cb..6e8c6db25 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -356,26 +356,6 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC } } - override suspend fun deposit( - request: RequestDepositBody - ): TransferResult? { - return withContext(ProxyDispatchers.wallet) { - webClient.post() - .uri("$baseUrl/deposit/${request.amount}_${request.chain}_${request.symbol}/${request.receiverUuid}_${request.receiverWalletType}") { - it.apply { - request.description?.let { description -> queryParam("description", description) } - request.transferRef?.let { transferRef -> queryParam("transferRef", transferRef) } - request.gatewayUuid?.let { gatewayUuid -> queryParam("gatewayUuid", gatewayUuid) } - }.build() - }.accept(MediaType.APPLICATION_JSON) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) - .retrieve() - .onStatus({ t -> t.isError }, { it.createException() }) - .bodyToMono() - .awaitFirstOrNull() - } - } - override suspend fun requestWithdraw( token: String, request: RequestWithdrawBody diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt index 7d758e1f5..33e688acf 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt @@ -216,7 +216,7 @@ class DepositService( suspend fun fetchDepositData( gatewayUuid: String?, symbol: String, - depositType: co.nilin.opex.wallet.core.model.DepositType, + depositType: DepositType, depositCommand: Deposit, ): GatewayData { From feba610cd3541d79906ff88f2254d6d1e86e5f11 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sat, 16 May 2026 21:04:42 +0330 Subject: [PATCH 29/56] Update swagger data for market controller --- .../binance/controller/WalletController.kt | 1 + .../ports/opex/controller/MarketController.kt | 630 ++++++++++++++---- 2 files changed, 493 insertions(+), 138 deletions(-) diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt index 9b389bdf5..0bba97e39 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt @@ -6,6 +6,7 @@ import co.nilin.opex.api.ports.binance.data.AssetResponse import co.nilin.opex.api.ports.binance.data.AssetsEstimatedValue import co.nilin.opex.common.security.jwtAuthentication import co.nilin.opex.common.security.tokenValue +import jdk.internal.vm.annotation.Hidden import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.GetMapping diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt index 913e1cc1c..290c55827 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/MarketController.kt @@ -9,6 +9,7 @@ import co.nilin.opex.api.ports.opex.data.RecentTradeResponse import co.nilin.opex.common.OpexError import co.nilin.opex.common.utils.Interval import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema @@ -17,7 +18,11 @@ import io.swagger.v3.oas.annotations.tags.Tag import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import org.springframework.beans.factory.annotation.Value -import org.springframework.web.bind.annotation.* +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController import java.math.BigDecimal import java.time.ZoneId @@ -40,16 +45,23 @@ class MarketController( @GetMapping("/currency") @Operation( summary = "Get currencies", - description = """GET /opex/v1/market/currency. -Security: Public endpoint. No Bearer token is required.""", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Response body: +- Array of currency data. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = CurrencyData::class)) - )] + description = "Currencies returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = CurrencyData::class)) + ) + ] ) ] ) @@ -59,17 +71,24 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/pair") @Operation( - summary = "Get pairs", - description = """GET /opex/v1/market/pair. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get trading pairs", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Response body: +- Array of pair info. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = PairInfoResponse::class)) - )] + description = "Trading pairs returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = PairInfoResponse::class)) + ) + ] ) ] ) @@ -94,16 +113,26 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/chain") @Operation( summary = "Get chains", - description = """GET /opex/v1/market/chain. -Security: Public endpoint. No Bearer token is required.""", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Source of values: +- Chain names returned here should be used by clients when selecting chain-based fields in other APIs. + +Response body: +- Array of chain info. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = ChainInfo::class)) - )] + description = "Chains returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = ChainInfo::class)) + ) + ] ) ] ) @@ -114,22 +143,49 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/currency/gateway") @Operation( summary = "Get currency gateways", - description = """GET /opex/v1/market/currency/gateway. -Security: Public endpoint. No Bearer token is required.""", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Behavior: +- `includeOffChainGateways` defaults to `true`. +- `includeOnChainGateways` defaults to `true`. +- Set either flag to `false` to exclude that gateway type. + +Response body: +- Array of currency gateway commands. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)) - )] + description = "Currency gateways returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)) + ) + ] ) ] ) suspend fun getCurrencyGateways( - @RequestParam(defaultValue = "true") includeOffChainGateways: Boolean, - @RequestParam(defaultValue = "true") includeOnChainGateways: Boolean + @Parameter( + name = "includeOffChainGateways", + description = "Whether OffChain gateways should be included. Defaults to true.", + required = false, + schema = Schema(type = "boolean", defaultValue = "true") + ) + @RequestParam(name = "includeOffChainGateways", defaultValue = "true") + includeOffChainGateways: Boolean, + + @Parameter( + name = "includeOnChainGateways", + description = "Whether OnChain gateways should be included. Defaults to true.", + required = false, + schema = Schema(type = "boolean", defaultValue = "true") + ) + @RequestParam(name = "includeOnChainGateways", defaultValue = "true") + includeOnChainGateways: Boolean ): List { return walletProxy.getGateWays(includeOffChainGateways, includeOnChainGateways) } @@ -137,16 +193,23 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/fee") @Operation( summary = "Get fee configs", - description = """GET /opex/v1/market/fee. -Security: Public endpoint. No Bearer token is required.""", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Response body: +- Array of fee config data. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = FeeConfig::class)) - )] + description = "Fee configs returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = FeeConfig::class)) + ) + ] ) ] ) @@ -157,22 +220,58 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/stats") @Operation( summary = "Get market stats", - description = """GET /opex/v1/market/stats. -Security: Public endpoint. No Bearer token is required.""", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Behavior: +- `interval` uses interval labels such as `1d`, `1w`, `1M`, or `3M`. +- If `interval` is invalid, the service falls back to `1w`. +- `limit` defaults to `100`. +- `limit` is clamped to the range `1..1000`. + +Response body: +- Market statistics response. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - schema = Schema(implementation = MarketInfoResponse::class) - )] + description = "Market stats returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = MarketStatResponse::class) + ) + ] ) ] ) suspend fun getMarketStats( - @RequestParam interval: String, - @RequestParam(required = false) limit: Int? + @Parameter( + name = "interval", + description = "Interval label. Invalid values fall back to 1w.", + required = true, + schema = Schema( + type = "string", + allowableValues = [ + "1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", + "24h", "1d", "3d", "7d", "1w", "1M", "3M", "1Y" + ] + ), + example = "1w" + ) + @RequestParam(name = "interval") + interval: String, + + @Parameter( + name = "limit", + description = "Optional result limit. Defaults to 100 and is clamped to 1..1000.", + required = false, + schema = Schema(type = "integer", format = "int32", defaultValue = "100"), + example = "100" + ) + @RequestParam(name = "limit", required = false) + limit: Int? ): MarketStatResponse = coroutineScope { val intervalEnum = Interval.findByLabel(interval) ?: Interval.Week val validLimit = getValidLimit(limit) @@ -202,7 +301,49 @@ Security: Public endpoint. No Bearer token is required.""", } @GetMapping("/info") - suspend fun getMarketInfo(@RequestParam interval: String): MarketInfoResponse { + @Operation( + summary = "Get market info", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Behavior: +- `interval` uses interval labels such as `1d`, `1w`, `1M`, or `3M`. +- If `interval` is invalid, the service falls back to `3M`. + +Response body: +- Market info response. + """, + responses = [ + ApiResponse( + responseCode = "200", + description = "Market info returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = MarketInfoResponse::class) + ) + ] + ) + ] + ) + suspend fun getMarketInfo( + @Parameter( + name = "interval", + description = "Interval label. Invalid values fall back to 3M.", + required = true, + schema = Schema( + type = "string", + allowableValues = [ + "1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", + "24h", "1d", "3d", "7d", "1w", "1M", "3M", "1Y" + ] + ), + example = "3M" + ) + @RequestParam(name = "interval") + interval: String + ): MarketInfoResponse { val intervalEnum = Interval.findByLabel(interval) ?: Interval.ThreeMonth return MarketInfoResponse( marketDataProxy.countActiveUsers(intervalEnum), @@ -213,25 +354,57 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/depth") @Operation( - summary = "Order book", - description = """GET /opex/v1/market/depth. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get order book", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Validation: +- `limit` must be one of: `5`, `10`, `20`, `50`, `100`, `500`, `1000`, `5000`. + +Behavior: +- `limit` defaults to `100` when omitted. + +Response body: +- Order book response. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - schema = Schema(implementation = OrderBookResponse::class) - )] + description = "Order book returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = OrderBookResponse::class) + ) + ] ) ] ) suspend fun orderBook( - @RequestParam + @Parameter( + name = "symbol", + description = "Market symbol.", + required = true, + example = "BTCUSDT" + ) + @RequestParam(name = "symbol") symbol: String, - @RequestParam(required = false) - limit: Int? // Default 100; max 5000. Valid limits:[5, 10, 20, 50, 100, 500, 1000, 5000] + + @Parameter( + name = "limit", + description = "Optional order book limit. Defaults to 100.", + required = false, + schema = Schema( + type = "integer", + format = "int32", + defaultValue = "100", + allowableValues = ["5", "10", "20", "50", "100", "500", "1000", "5000"] + ), + example = "100" + ) + @RequestParam(name = "limit", required = false) + limit: Int? ): OrderBookResponse { val validLimit = limit ?: 100 if (!orderBookValidLimits.contains(validLimit)) @@ -265,25 +438,52 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/trades") @Operation( - summary = "Recent trades", - description = """GET /opex/v1/market/trades. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get recent trades", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Validation: +- `limit` must be between `1` and `1000`. + +Behavior: +- `limit` defaults to `500` when omitted. + +Response body: +- Array of recent trades. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = RecentTradeResponse::class)) - )] + description = "Recent trades returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = RecentTradeResponse::class)) + ) + ] ) ] ) suspend fun recentTrades( - @RequestParam + @Parameter( + name = "symbol", + description = "Market symbol.", + required = true, + example = "BTCUSDT" + ) + @RequestParam(name = "symbol") symbol: String, - @RequestParam(required = false) - limit: Int? // Default 500; max 1000. + + @Parameter( + name = "limit", + description = "Optional recent-trade limit. Defaults to 500. Valid range: 1..1000.", + required = false, + schema = Schema(type = "integer", format = "int32", defaultValue = "500", minimum = "1", maximum = "1000"), + example = "500" + ) + @RequestParam(name = "limit", required = false) + limit: Int? ): List { val validLimit = limit ?: 500 if (validLimit !in 1..1000) @@ -305,24 +505,65 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/ticker/{duration:24h|7d|1M}") @Operation( - summary = "Price change", - description = """GET /opex/v1/market/ticker/{duration:24h|7d|1M}. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get price change tickers", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Validation: +- `duration` must be one of: `24h`, `7d`, `1M`. + +Behavior: +- If `symbol` is omitted, all symbols are returned. +- If `quote` is provided, results are filtered by quote currency. + +Source of values: +- Quote values should come from `/opex/v1/market/currencyInfo/quotes`. + +Response body: +- Array of price change data. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = PriceChange::class)) - )] + description = "Price changes returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = PriceChange::class)) + ) + ] ) ] ) suspend fun priceChange( - @PathVariable duration: String, - @RequestParam(required = false) symbol: String?, - @RequestParam(required = false) quote: String? + @Parameter( + name = "duration", + description = "Ticker duration.", + required = true, + schema = Schema(type = "string", allowableValues = ["24h", "7d", "1M"]), + example = "24h" + ) + @PathVariable("duration") + duration: String, + + @Parameter( + name = "symbol", + description = "Optional market symbol. If omitted, all symbols are returned.", + required = false, + example = "BTCUSDT" + ) + @RequestParam(name = "symbol", required = false) + symbol: String?, + + @Parameter( + name = "quote", + description = "Optional quote currency filter.", + required = false, + example = "USDT" + ) + @RequestParam(name = "quote", required = false) + quote: String? ): List { if (!validDurations.contains(duration)) OpexError.InvalidPriceChangeDuration.exception() @@ -347,37 +588,66 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/ticker/price") @Operation( - summary = "Price ticker", - description = """GET /opex/v1/market/ticker/price. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get price ticker", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Behavior: +- If `symbol` is omitted, prices for all available symbols are returned. + +Response body: +- Array of price ticker data. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = PriceTicker::class)) - )] + description = "Price ticker returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = PriceTicker::class)) + ) + ] ) ] ) - suspend fun priceTicker(@RequestParam(required = false) symbol: String?): List { + suspend fun priceTicker( + @Parameter( + name = "symbol", + description = "Optional market symbol. If omitted, all available symbols are returned.", + required = false, + example = "BTCUSDT" + ) + @RequestParam(name = "symbol", required = false) + symbol: String? + ): List { return marketDataProxy.lastPrice(symbol) } @GetMapping("/currencyInfo/quotes") @Operation( summary = "Get quote currencies", - description = """GET /opex/v1/market/currencyInfo/quotes. -Security: Public endpoint. No Bearer token is required.""", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Source of values: +- Returned values can be used as the `quote` filter in ticker endpoints. + +Response body: +- Array of quote currency strings. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(type = "string")) - )] + description = "Quote currencies returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(type = "string")) + ) + ] ) ] ) @@ -387,35 +657,89 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/klines") @Operation( - summary = "Klines", - description = """GET /opex/v1/market/klines. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get klines", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Validation: +- `interval` must match one of the supported interval labels. +- `limit` must be between `1` and `1000`. + +Behavior: +- `limit` defaults to `500` when omitted. +- `startTime` and `endTime` are Unix timestamps in milliseconds. +- Response rows are nested arrays in candlestick order. + +Response body: +- Nested array of kline rows. + """, responses = [ ApiResponse( responseCode = "200", - description = "Returned successfully.", + description = "Klines returned successfully.", content = [ Content( mediaType = "application/json", - array = ArraySchema( - schema = Schema(type = "array") - ) + array = ArraySchema(schema = Schema(type = "array")) ) ] ) ] ) suspend fun klines( - @RequestParam + @Parameter( + name = "symbol", + description = "Market symbol.", + required = true, + example = "BTCUSDT" + ) + @RequestParam(name = "symbol") symbol: String, - @RequestParam + + @Parameter( + name = "interval", + description = "Candlestick interval label.", + required = true, + schema = Schema( + type = "string", + allowableValues = [ + "1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", + "24h", "1d", "3d", "7d", "1w", "1M", "3M", "1Y" + ] + ), + example = "1h" + ) + @RequestParam(name = "interval") interval: String, - @RequestParam(required = false) + + @Parameter( + name = "startTime", + description = "Optional start time as Unix timestamp in milliseconds.", + required = false, + schema = Schema(type = "integer", format = "int64") + ) + @RequestParam(name = "startTime", required = false) startTime: Long?, - @RequestParam(required = false) + + @Parameter( + name = "endTime", + description = "Optional end time as Unix timestamp in milliseconds.", + required = false, + schema = Schema(type = "integer", format = "int64") + ) + @RequestParam(name = "endTime", required = false) endTime: Long?, - @RequestParam(required = false) - limit: Int? // Default 500; max 1000. + + @Parameter( + name = "limit", + description = "Optional kline limit. Defaults to 500. Valid range: 1..1000.", + required = false, + schema = Schema(type = "integer", format = "int32", defaultValue = "500", minimum = "1", maximum = "1000"), + example = "500" + ) + @RequestParam(name = "limit", required = false) + limit: Int? ): List> { val validLimit = limit ?: 500 if (validLimit !in 1..1000) @@ -448,43 +772,56 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/basic-data") @Operation( - summary = "Get basic data", - description = """GET /opex/v1/market/basic-data. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get basic market data", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Response body: +- Basic market data. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - schema = Schema(implementation = MarketBasicData::class) - )] + description = "Basic market data returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = MarketBasicData::class) + ) + ] ) ] ) suspend fun getBasicData(): MarketBasicData { val quoteCurrencies = walletProxy.getQuoteCurrencies() return MarketBasicData( - (quoteCurrencies.map { it.currency }), - (quoteCurrencies.filter { it.isReference }.map { it.currency }), + quoteCurrencies.map { it.currency }, + quoteCurrencies.filter { it.isReference }.map { it.currency }, userActivityReferenceCurrency - ) } @GetMapping("/withdraw-limits") @Operation( summary = "Get withdraw limits", - description = """GET /opex/v1/market/withdraw-limits. -Security: Public endpoint. No Bearer token is required.""", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Response body: +- Array of withdraw limit configs. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = WithdrawLimitConfig::class)) - )] + description = "Withdraw limits returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = WithdrawLimitConfig::class)) + ) + ] ) ] ) @@ -494,22 +831,39 @@ Security: Public endpoint. No Bearer token is required.""", @GetMapping("/gateway/{gatewayUuid}/terminal") @Operation( - summary = "Get gateway terminal", - description = """GET /opex/v1/market/gateway/{gatewayUuid}/terminal. -Security: Public endpoint. No Bearer token is required.""", + summary = "Get gateway terminals", + description = """ +Security: +- Public endpoint. No Bearer token is required. + +Source of values: +- `gatewayUuid` should come from currency gateway data. + +Response body: +- Array of terminal commands, or null if no data is returned. + """, responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)) - )] + description = "Gateway terminals returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)) + ) + ] ) ] ) suspend fun getGatewayTerminal( - @PathVariable("gatewayUuid") gatewayUuid: String + @Parameter( + name = "gatewayUuid", + description = "Gateway UUID.", + required = true, + example = "ofg-uuid-sample" + ) + @PathVariable("gatewayUuid") + gatewayUuid: String ): List? { return walletProxy.getGatewayTerminal(gatewayUuid) } From 51cbd20fb70fcc8b94e0e11b729c1bc30eea8ebd Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 19 May 2026 16:05:10 +0330 Subject: [PATCH 30/56] Tag depricated apis --- api/api-ports/api-binance-rest/pom.xml | 5 ++ .../binance/controller/AccountController.kt | 3 + .../binance/controller/LandingController.kt | 5 +- .../binance/controller/MarketController.kt | 22 +++++-- .../binance/controller/WalletController.kt | 2 + .../ports/opex/controller/OrderController.kt | 66 +++++++++++++++++-- 6 files changed, 90 insertions(+), 13 deletions(-) diff --git a/api/api-ports/api-binance-rest/pom.xml b/api/api-ports/api-binance-rest/pom.xml index fd5fdffe3..bff6d12c2 100644 --- a/api/api-ports/api-binance-rest/pom.xml +++ b/api/api-ports/api-binance-rest/pom.xml @@ -98,5 +98,10 @@ swagger-annotations 1.5.20 + + org.springdoc + springdoc-openapi-starter-webflux-ui + 2.8.14 + diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/AccountController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/AccountController.kt index 1d146d47b..12c7af9c1 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/AccountController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/AccountController.kt @@ -14,6 +14,7 @@ import io.swagger.annotations.ApiParam import io.swagger.annotations.ApiResponse import io.swagger.annotations.Example import io.swagger.annotations.ExampleProperty +import io.swagger.v3.oas.annotations.Hidden import org.springframework.http.MediaType import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext @@ -24,6 +25,8 @@ import java.time.ZoneId import java.util.* @RestController +@Hidden +@Deprecated("") class AccountController( val queryHandler: MarketUserDataProxy, val matchingGatewayProxy: MatchingGatewayProxy, diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/LandingController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/LandingController.kt index b6524c586..9666453e1 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/LandingController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/LandingController.kt @@ -10,6 +10,7 @@ import co.nilin.opex.api.ports.binance.data.GlobalPriceResponse import co.nilin.opex.api.ports.binance.data.MarketInfoResponse import co.nilin.opex.api.ports.binance.data.MarketStatResponse import co.nilin.opex.common.utils.Interval +import io.swagger.v3.oas.annotations.Hidden import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import org.slf4j.LoggerFactory @@ -19,7 +20,9 @@ import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import java.math.BigDecimal -@RestController // Custom service +@RestController +@Hidden +@Deprecated("")// Custom service @RequestMapping("/v1/landing") class LandingController( private val marketStatProxy: MarketStatProxy, diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/MarketController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/MarketController.kt index c83f41bac..f93715b5b 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/MarketController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/MarketController.kt @@ -9,6 +9,8 @@ import co.nilin.opex.api.core.spi.SymbolMapper import co.nilin.opex.api.ports.binance.data.* import co.nilin.opex.common.OpexError import co.nilin.opex.common.utils.Interval +import io.swagger.v3.oas.annotations.Hidden +import io.swagger.v3.oas.annotations.tags.Tag import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope import org.springframework.web.bind.annotation.GetMapping @@ -18,7 +20,6 @@ import org.springframework.web.bind.annotation.RestController import java.math.BigDecimal import java.security.Principal import java.time.ZoneId - @RestController("binanceMarketController") class MarketController( private val accountantProxy: AccountantProxy, @@ -35,6 +36,8 @@ class MarketController( // 500 - 5 // 1000 - 10 // 5000 - 50 + @Hidden + @Deprecated("Deprecated") @GetMapping("/v3/depth") suspend fun orderBook( @RequestParam @@ -72,7 +75,8 @@ class MarketController( val lastOrder = marketDataProxy.lastOrder(localSymbol) return OrderBookResponse(lastOrder?.orderId ?: -1, mappedBidOrders, mappedAskOrders) } - + @Hidden + @Deprecated("Deprecated") @GetMapping("/v3/trades") suspend fun recentTrades( principal: Principal, @@ -99,7 +103,8 @@ class MarketController( ) } } - + @Hidden + @Deprecated("Deprecated") @GetMapping("/v3/ticker/{duration:24h|7d|1M}") suspend fun priceChange( @PathVariable duration: String, @@ -137,7 +142,8 @@ class MarketController( return if (quote.isNullOrEmpty()) result else result.filter { it.quote.equals(quote, true) } } - + @Hidden + @Deprecated("Deprecated") // Weight // 1 for a single symbol // 2 when the symbol parameter is omitted @@ -150,7 +156,8 @@ class MarketController( symbolMapper.toInternalSymbol(symbol) ?: throw OpexError.SymbolNotFound.exception() return marketDataProxy.lastPrice(localSymbol).onEach { symbols[it.symbol]?.let { s -> it.symbol = s } } } - + @Hidden + @Deprecated("Deprecated") @GetMapping("/v3/exchangeInfo") suspend fun pairInfo( @RequestParam(required = false) @@ -198,7 +205,8 @@ class MarketController( // ) // } // } - + @Hidden + @Deprecated("Deprecated") // Custom service @GetMapping("/v3/currencyInfo/quotes") suspend fun getQuoteCurrencies(): List { @@ -206,8 +214,8 @@ class MarketController( .map { it.rightSideWalletSymbol } .distinct() } - // Weight(IP): 1 + @Tag(name = "Internal Charts") @GetMapping("/v3/klines") suspend fun klines( @RequestParam diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt index 0bba97e39..e21f99536 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/controller/WalletController.kt @@ -15,6 +15,8 @@ import org.springframework.web.bind.annotation.RestController import java.math.BigDecimal @RestController("walletBinanceController") +@io.swagger.v3.oas.annotations.Hidden +@Deprecated("") class WalletController( private val walletProxy: WalletProxy, private val marketDataProxy: MarketDataProxy, diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt index 7e379e03c..5cbff36b5 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt @@ -10,7 +10,6 @@ import co.nilin.opex.api.ports.opex.util.* import co.nilin.opex.common.OpexError import co.nilin.opex.common.security.jwtAuthentication import co.nilin.opex.common.security.tokenValue -import io.swagger.v3.oas.annotations.Parameter import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @@ -18,14 +17,36 @@ import java.math.BigDecimal import java.security.Principal import java.time.ZoneId import java.util.* +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/order") +@Tag(name = "Order", description = "Authenticated order creation, cancellation, query, and open order operations.") class OrderController( val queryHandler: MarketUserDataProxy, - val matchingGatewayProxy: MatchingGatewayProxy, + val matchingGatewayProxy: MatchingGatewayProxy ) { @PostMapping + @Operation( + summary = "Create new order", + description = """POST /opex/v1/order. +Security: Bearer user-token required. Required authority: PERM_order:write. + +Validation: For LIMIT orders, price and quantity are expected. For MARKET orders, use the quantity/quoteOrderQty combination supported by the backend validation. Stop order types require stopPrice.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = NewOrderResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_order:write. No response body.", content = [Content()]) + ] + ) suspend fun createNewOrder( @RequestParam symbol: String, @@ -44,6 +65,7 @@ class OrderController( @Parameter(description = "Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.") @RequestParam(required = false) stopPrice: BigDecimal?, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): NewOrderResponse { validateNewOrderParams(type, price, quantity, timeInForce, stopPrice, quoteOrderQty) @@ -63,6 +85,19 @@ class OrderController( } @PutMapping + @Operation( + summary = "Cancel order", + description = """PUT /opex/v1/order. +Security: Bearer user-token required. Required authority: PERM_order:write. + +Validation: Either `orderId` or `origClientOrderId` must be provided.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CancelOrderResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_order:write. No response body.", content = [Content()]) + ] + ) suspend fun cancelOrder( principal: Principal, @RequestParam @@ -71,6 +106,7 @@ class OrderController( orderId: Long?, @RequestParam(required = false) origClientOrderId: String?, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): CancelOrderResponse { if (orderId == null && origClientOrderId == null) @@ -112,6 +148,16 @@ class OrderController( } @GetMapping + @Operation( + summary = "Query order", + description = """GET /opex/v1/order. +Security: Bearer user-token required. Requires authenticated user JWT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = QueryOrderResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun queryOrder( principal: Principal, @RequestParam @@ -119,7 +165,7 @@ class OrderController( @RequestParam(required = false) orderId: Long?, @RequestParam(required = false) - origClientOrderId: String?, + origClientOrderId: String? ): QueryOrderResponse { return queryHandler.queryOrder(principal, symbol, orderId, origClientOrderId) ?.asQueryOrderResponse() @@ -128,6 +174,16 @@ class OrderController( } @GetMapping("/open") + @Operation( + summary = "Fetch open orders", + description = """GET /opex/v1/order/open. +Security: Bearer user-token required. Requires authenticated user JWT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = QueryOrderResponse::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun fetchOpenOrders( principal: Principal, @RequestParam(required = false) @@ -146,7 +202,7 @@ class OrderController( quantity: BigDecimal?, timeInForce: TimeInForce?, stopPrice: BigDecimal?, - quoteOrderQty: BigDecimal?, + quoteOrderQty: BigDecimal? ) { when (type) { OrderType.LIMIT -> { @@ -225,4 +281,4 @@ class OrderController( quoteQuantity ) -} \ No newline at end of file +} From 95c99b7936dcbff5c6866061b1570d28c56b6bb0 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 19 May 2026 20:10:38 +0330 Subject: [PATCH 31/56] Update swagger data about order services --- .../ports/opex/controller/OrderController.kt | 391 ++++++++++++++---- 1 file changed, 302 insertions(+), 89 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt index 5cbff36b5..aa74d899d 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt @@ -10,66 +10,163 @@ import co.nilin.opex.api.ports.opex.util.* import co.nilin.opex.common.OpexError import co.nilin.opex.common.security.jwtAuthentication import co.nilin.opex.common.security.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* -import java.math.BigDecimal -import java.security.Principal -import java.time.ZoneId -import java.util.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* +import java.math.BigDecimal +import java.security.Principal +import java.time.ZoneId +import java.util.* @RestController @RequestMapping("/opex/v1/order") -@Tag(name = "Order", description = "Authenticated order creation, cancellation, query, and open order operations.") +@Tag( + name = "Order", + description = "Create, cancel, query, and list authenticated user's orders." +) class OrderController( val queryHandler: MarketUserDataProxy, - val matchingGatewayProxy: MatchingGatewayProxy + val matchingGatewayProxy: MatchingGatewayProxy, ) { + @PostMapping @Operation( - summary = "Create new order", - description = """POST /opex/v1/order. -Security: Bearer user-token required. Required authority: PERM_order:write. + summary = "Create order", + description = """ +Security: +- Bearer user-token is required. +- Required permission: PERM_order:write. -Validation: For LIMIT orders, price and quantity are expected. For MARKET orders, use the quantity/quoteOrderQty combination supported by the backend validation. Stop order types require stopPrice.""", +Validation: +- symbol, side, and type are required. +- side values: BUY, SELL. +- type values: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- timeInForce values: GTC, IOC, FOK. +- LIMIT(*) requires price, quantity, and timeInForce. +- MARKET requires quantity or quoteOrderQty. +- STOP_LOSS requires quantity and stopPrice. +- STOP_LOSS_LIMIT requires price, quantity, stopPrice, and timeInForce. +- TAKE_PROFIT requires quantity and stopPrice. +- TAKE_PROFIT_LIMIT requires price, quantity, stopPrice, and timeInForce. +- LIMIT_MAKER requires price and quantity. + +Behavior: +- Optional parameters that are not applicable to the selected order type should be omitted. +- Do not send the literal string "null" for optional numeric parameters. + +Response body: +- NewOrderResponse. + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = NewOrderResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_order:write. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Order created successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = NewOrderResponse::class) + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. No response body.", + content = [Content()] + ) ] ) suspend fun createNewOrder( - @RequestParam - symbol: String, - @RequestParam - side: OrderSide, - @RequestParam - type: OrderType, - @RequestParam(required = false) - timeInForce: TimeInForce?, - @RequestParam(required = false) - quantity: BigDecimal?, - @RequestParam(required = false) - quoteOrderQty: BigDecimal?, - @RequestParam(required = false) - price: BigDecimal?, - @Parameter(description = "Used with STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.") - @RequestParam(required = false) - stopPrice: BigDecimal?, + @Parameter( + name = "symbol", + description = "Trading pair symbol.", + required = true, + `in` = ParameterIn.QUERY, + example = "BTC_USDT" + ) + @RequestParam symbol: String, + + @Parameter( + name = "side", + description = "Order side. Values: BUY, SELL.", + required = true, + `in` = ParameterIn.QUERY, + schema = Schema(implementation = OrderSide::class) + ) + @RequestParam side: OrderSide, + + @Parameter( + name = "type", + description = "Order type. Values: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER.", + required = true, + `in` = ParameterIn.QUERY, + schema = Schema(implementation = OrderType::class) + ) + @RequestParam type: OrderType, + + @Parameter( + name = "timeInForce", + description = "Optional time-in-force. Values: GTC, IOC, FOK. Required for LIMIT, STOP_LOSS_LIMIT, and TAKE_PROFIT_LIMIT orders.", + required = false, + `in` = ParameterIn.QUERY, + schema = Schema(implementation = TimeInForce::class) + ) + @RequestParam(required = false) timeInForce: TimeInForce?, + + @Parameter( + name = "quantity", + description = "Optional base quantity. Required for LIMIT, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, and LIMIT_MAKER orders. For MARKET orders, quantity or quoteOrderQty must be provided.", + required = false, + `in` = ParameterIn.QUERY, + example = "0.001" + ) + @RequestParam(required = false) quantity: BigDecimal?, + + @Parameter( + name = "quoteOrderQty", + description = "Optional quote quantity for MARKET orders when quantity is not provided.", + required = false, + `in` = ParameterIn.QUERY, + example = "10.0" + ) + @RequestParam(required = false) quoteOrderQty: BigDecimal?, + + @Parameter( + name = "price", + description = "Optional order price. Required for LIMIT, STOP_LOSS_LIMIT, TAKE_PROFIT_LIMIT, and LIMIT_MAKER orders.", + required = false, + `in` = ParameterIn.QUERY, + example = "10.0" + ) + @RequestParam(required = false) price: BigDecimal?, + + @Parameter( + name = "stopPrice", + description = "Optional stop price. Required for STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, and TAKE_PROFIT_LIMIT orders.", + required = false, + `in` = ParameterIn.QUERY, + example = "9.5" + ) + @RequestParam(required = false) stopPrice: BigDecimal?, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): NewOrderResponse { validateNewOrderParams(type, price, quantity, timeInForce, stopPrice, quoteOrderQty) - matchingGatewayProxy.createNewOrder( securityContext.jwtAuthentication().name, symbol, @@ -87,34 +184,82 @@ Validation: For LIMIT orders, price and quantity are expected. For MARKET orders @PutMapping @Operation( summary = "Cancel order", - description = """PUT /opex/v1/order. -Security: Bearer user-token required. Required authority: PERM_order:write. + description = """ +Security: +- Bearer user-token is required. +- Required permission: PERM_order:write. -Validation: Either `orderId` or `origClientOrderId` must be provided.""", +Validation: +- symbol is required. +- At least one lookup identifier is required: orderId or origClientOrderId. + +Behavior: +- Already canceled orders return a canceled response. +- Rejected, expired, or filled orders cannot be canceled. + +Response body: +- CancelOrderResponse. + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = CancelOrderResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_order:write. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Order canceled successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = CancelOrderResponse::class) + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. No response body.", + content = [Content()] + ) ] ) suspend fun cancelOrder( + @Parameter(hidden = true) principal: Principal, - @RequestParam - symbol: String, - @RequestParam(required = false) - orderId: Long?, - @RequestParam(required = false) - origClientOrderId: String?, + + @Parameter( + name = "symbol", + description = "Trading pair symbol.", + required = true, + `in` = ParameterIn.QUERY, + example = "BTC_USDT" + ) + @RequestParam symbol: String, + + @Parameter( + name = "orderId", + description = "Optional numeric order ID. Required when origClientOrderId is not provided.", + required = false, + `in` = ParameterIn.QUERY, + example = "1" + ) + @RequestParam(required = false) orderId: Long?, + + @Parameter( + name = "origClientOrderId", + description = "Optional original client order ID. Required when orderId is not provided.", + required = false, + `in` = ParameterIn.QUERY, + example = "client-order-id-sample" + ) + @RequestParam(required = false) origClientOrderId: String?, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): CancelOrderResponse { - if (orderId == null && origClientOrderId == null) - throw OpexError.BadRequest.exception("'orderId' or 'origClientOrderId' must be sent") - - val order = queryHandler.queryOrder(principal, symbol, orderId, origClientOrderId) - ?: throw OpexError.OrderNotFound.exception() - + if (orderId == null && origClientOrderId == null) throw OpexError.BadRequest.exception("'orderId' or 'origClientOrderId' must be sent") + val order = queryHandler.queryOrder(principal, symbol, orderId, origClientOrderId) ?: throw OpexError.OrderNotFound.exception() val response = CancelOrderResponse( symbol, origClientOrderId, @@ -130,13 +275,9 @@ Validation: Either `orderId` or `origClientOrderId` must be provided.""", order.type.asOrderType(), order.direction.asOrderSide() ) - - if (order.status == OrderStatus.CANCELED) - return response - + if (order.status == OrderStatus.CANCELED) return response if (order.status.equalsAny(OrderStatus.REJECTED, OrderStatus.EXPIRED, OrderStatus.FILLED)) throw OpexError.CancelOrderNotAllowed.exception() - matchingGatewayProxy.cancelOrder( order.ouid, principal.name, @@ -149,23 +290,67 @@ Validation: Either `orderId` or `origClientOrderId` must be provided.""", @GetMapping @Operation( - summary = "Query order", - description = """GET /opex/v1/order. -Security: Bearer user-token required. Requires authenticated user JWT.""", + summary = "Get order", + description = """ +Security: +- Bearer user-token is required. + +Validation: +- symbol is required. +- At least one lookup identifier should be provided: orderId or origClientOrderId. + +Response body: +- QueryOrderResponse. + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = QueryOrderResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Order returned successfully.", + content = [ + Content( + mediaType = "application/json", + schema = Schema(implementation = QueryOrderResponse::class) + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. No response body.", + content = [Content()] + ) ] ) suspend fun queryOrder( + @Parameter(hidden = true) principal: Principal, - @RequestParam - symbol: String, - @RequestParam(required = false) - orderId: Long?, - @RequestParam(required = false) - origClientOrderId: String? + + @Parameter( + name = "symbol", + description = "Trading pair symbol.", + required = true, + `in` = ParameterIn.QUERY, + example = "BTC_USDT" + ) + @RequestParam symbol: String, + + @Parameter( + name = "orderId", + description = "Optional numeric order ID.", + required = false, + `in` = ParameterIn.QUERY, + example = "1" + ) + @RequestParam(required = false) orderId: Long?, + + @Parameter( + name = "origClientOrderId", + description = "Optional original client order ID.", + required = false, + `in` = ParameterIn.QUERY, + example = "client-order-id-sample" + ) + @RequestParam(required = false) origClientOrderId: String?, ): QueryOrderResponse { return queryHandler.queryOrder(principal, symbol, orderId, origClientOrderId) ?.asQueryOrderResponse() @@ -175,21 +360,58 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", @GetMapping("/open") @Operation( - summary = "Fetch open orders", - description = """GET /opex/v1/order/open. -Security: Bearer user-token required. Requires authenticated user JWT.""", + summary = "List open orders", + description = """ +Security: +- Bearer user-token is required. + +Behavior: +- symbol is optional. When omitted, open orders are returned without symbol filtering. +- limit is optional. + +Response body: +- Array of QueryOrderResponse. + """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = QueryOrderResponse::class)))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Open orders returned successfully.", + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = QueryOrderResponse::class)) + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. No response body.", + content = [Content()] + ) ] ) suspend fun fetchOpenOrders( + @Parameter(hidden = true) principal: Principal, - @RequestParam(required = false) - symbol: String?, - @RequestParam(required = false) - limit: Int? + + @Parameter( + name = "symbol", + description = "Optional trading pair symbol filter.", + required = false, + `in` = ParameterIn.QUERY, + example = "BTC_USDT" + ) + @RequestParam(required = false) symbol: String?, + + @Parameter( + name = "limit", + description = "Optional maximum number of open orders to return.", + required = false, + `in` = ParameterIn.QUERY, + example = "10" + ) + @RequestParam(required = false) limit: Int? ): List { return queryHandler.openOrders(principal, symbol, limit).map { it.asQueryOrderResponse().apply { symbol?.let { s -> this.symbol = s } } @@ -202,7 +424,7 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", quantity: BigDecimal?, timeInForce: TimeInForce?, stopPrice: BigDecimal?, - quoteOrderQty: BigDecimal? + quoteOrderQty: BigDecimal?, ) { when (type) { OrderType.LIMIT -> { @@ -210,38 +432,30 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", checkDecimal(quantity, "quantity") checkNull(timeInForce, "timeInForce") } - OrderType.MARKET -> { - if (quantity == null) - checkDecimal(quoteOrderQty, "quoteOrderQty") - else - checkDecimal(quantity, "quantity") + if (quantity == null) checkDecimal(quoteOrderQty, "quoteOrderQty") + else checkDecimal(quantity, "quantity") } - OrderType.STOP_LOSS -> { checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") } - OrderType.STOP_LOSS_LIMIT -> { checkDecimal(price, "price") checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") checkNull(timeInForce, "timeInForce") } - OrderType.TAKE_PROFIT -> { checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") } - OrderType.TAKE_PROFIT_LIMIT -> { checkDecimal(price, "price") checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") checkNull(timeInForce, "timeInForce") } - OrderType.LIMIT_MAKER -> { checkDecimal(price, "price") checkDecimal(quantity, "quantity") @@ -280,5 +494,4 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", status.isWorking(), quoteQuantity ) - } From f5d0e1bc7a0b818a801da25b5b991262b87fd124 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Wed, 20 May 2026 17:30:14 +0330 Subject: [PATCH 32/56] Update swagger data about profile services --- .../opex/controller/ProfileAdminController.kt | 138 +++++++++++++++++- .../opex/controller/ProfileController.kt | 77 +++++++++- .../dao/ProfileApprovalRequestRepository.kt | 2 +- 3 files changed, 205 insertions(+), 12 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt index 4606f77dc..8753429c8 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt @@ -7,15 +7,42 @@ import co.nilin.opex.api.ports.opex.util.tokenValue import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/profile") +@Tag(name = "Profile Admin", description = "Admin profile and approval request operations.\n\nAllowed values:\n- nationality: IRANIAN, NON_IRANIAN.\n- gender: FEMALE, MALE.\n- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED.\n- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3.\n- approval request status: PENDING, APPROVED, REJECTED.") class ProfileAdminController(private val profileProxy: ProfileProxy) { @PostMapping + @Operation( + summary = "Get profiles", + description = """POST /opex/v1/admin/profile. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED. +- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3. +- approval request status: PENDING, APPROVED, REJECTED.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = Profile::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getProfiles( @RequestBody profileRequest: ProfileRequest, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return profileProxy.getProfiles( securityContext.jwtAuthentication().tokenValue(), @@ -24,18 +51,60 @@ class ProfileAdminController(private val profileProxy: ProfileProxy) { } @GetMapping("/{uuid}") + @Operation( + summary = "Get profile", + description = """GET /opex/v1/admin/profile/{uuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED. +- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3. +- approval request status: PENDING, APPROVED, REJECTED.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Profile::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getProfile( + @Parameter(name = "uuid", description = "User/profile/terminal UUID depending on the endpoint context.", required = true) @PathVariable uuid: String, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): Profile { return profileProxy.getProfileAdmin(securityContext.jwtAuthentication().tokenValue(), uuid) } @GetMapping("/history/{uuid}") + @Operation( + summary = "Get profile history", + description = """GET /opex/v1/admin/profile/history/{uuid}. +Behavior: `limit` defaults to 10 and `offset` defaults to 0 when omitted. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED. +- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3. +- approval request status: PENDING, APPROVED, REJECTED.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = ProfileHistory::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getProfileHistory( + @Parameter(name = "uuid", description = "User UUID depending on the endpoint context.", required = true) @PathVariable uuid: String, - @RequestParam offset: Int?, @RequestParam limit: Int?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "offset", description = "Optional page offset.", required = false) + @RequestParam offset: Int?, + @Parameter(name = "limit", description = "Optional page size.", required = false) + @RequestParam limit: Int?, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return profileProxy.getProfileHistory( securityContext.jwtAuthentication().tokenValue(), @@ -46,24 +115,79 @@ class ProfileAdminController(private val profileProxy: ProfileProxy) { } @PostMapping("/approval-requests") + @Operation( + summary = "Get approval requests", + description = """POST /opex/v1/admin/profile/approval-requests. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED. +- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3. +- approval request status: PENDING, APPROVED, REJECTED.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = ProfileApprovalAdminResponse::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getApprovalRequests( @RequestBody request: ProfileApprovalRequestFilter, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return profileProxy.getProfileApprovalRequests(securityContext.jwtAuthentication().tokenValue(), request) } @GetMapping("/approval-request/{id}") + @Operation( + summary = "Get approval request", + description = """GET /opex/v1/admin/profile/approval-request/{id}. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED. +- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3. +- approval request status: PENDING, APPROVED, REJECTED.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileApprovalAdminResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getApprovalRequest( + @Parameter(name = "id", description = "Numeric resource ID.", required = true) @PathVariable("id") id: Long, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): ProfileApprovalAdminResponse { return profileProxy.getProfileApprovalRequest(securityContext.jwtAuthentication().tokenValue(), id) } @PutMapping("/approval-request") + @Operation( + summary = "Update approval request status", + description = """PUT /opex/v1/admin/profile/approval-request. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED. +- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3. +- approval request status: PENDING, APPROVED, REJECTED.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileApprovalAdminResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun updateApprovalRequestStatus( @RequestBody changeRequestStatusBody: UpdateApprovalRequestBody, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): ProfileApprovalAdminResponse { return profileProxy.updateProfileApprovalRequest( @@ -71,4 +195,4 @@ class ProfileAdminController(private val profileProxy: ProfileProxy) { changeRequestStatusBody ) } -} \ No newline at end of file +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt index 9679d60e4..816f3ba16 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt @@ -9,22 +9,53 @@ import co.nilin.opex.api.ports.opex.util.tokenValue import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/profile") +@Tag(name = "Profile", description = "Authenticated user profile operations.") class ProfileController( - val profileProxy: ProfileProxy, + val profileProxy: ProfileProxy ) { @GetMapping("/personal-data") - suspend fun getProfile(@CurrentSecurityContext securityContext: SecurityContext): ProfileResponse { + @Operation( + summary = "Get profile", + description = """GET /opex/v1/profile/personal-data. +Security: Bearer user-token required. Requires authenticated user JWT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) + suspend fun getProfile(@Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext): ProfileResponse { return profileProxy.getProfile(securityContext.jwtAuthentication().tokenValue()).toProfileResponse() } @PutMapping("/completion") + @Operation( + summary = "Complete profile", + description = """PUT /opex/v1/profile/completion. +Security: Bearer user-token required. Requires authenticated user JWT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun completeProfile( @RequestBody completeProfileRequest: CompleteProfileRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): ProfileResponse? { return profileProxy.completeProfile(securityContext.jwtAuthentication().tokenValue(), completeProfileRequest) @@ -32,16 +63,43 @@ class ProfileController( } @PostMapping("/contact/update/otp-request") + @Operation( + summary = "Request contact update", + description = """POST /opex/v1/profile/contact/update/otp-request. +Behavior: Starts contact update flow and returns OTP delivery information. +Security: Bearer user-token required. Requires authenticated user JWT. +Validation: Exactly one of `mobile` or `email` must be provided. Providing both or neither is invalid. +""", + + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TempOtpResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun requestContactUpdate( @RequestBody request: ContactUpdateRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): TempOtpResponse { return profileProxy.requestContactUpdate(securityContext.jwtAuthentication().tokenValue(), request) } @PatchMapping("/contact/update/otp-verification") + @Operation( + summary = "Confirm contact update", + description = """PATCH /opex/v1/profile/contact/update/otp-verification. +Validation: Verification request must contain the OTP value and target contact details required by the request schema. +Security: Bearer user-token required. Requires authenticated user JWT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun confirmContactUpdate( @RequestBody request: ContactUpdateConfirmRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ) { profileProxy.confirmContactUpdate(securityContext.jwtAuthentication().tokenValue(), request) @@ -49,8 +107,19 @@ class ProfileController( } @GetMapping("/approval-request") - suspend fun getApprovalRequest(@CurrentSecurityContext securityContext: SecurityContext): ProfileApprovalRequestUserResponse { + @Operation( + summary = "Get approval request", + description = """GET /opex/v1/profile/approval-request. +Security: Bearer user-token required. Requires authenticated user JWT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileApprovalRequestUserResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) + suspend fun getApprovalRequest(@Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext): ProfileApprovalRequestUserResponse { return profileProxy.getUserProfileApprovalRequest(securityContext.jwtAuthentication().tokenValue()) .toProfileApprovalRequestUserResponse() } -} \ No newline at end of file +} diff --git a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt index 9b8486e8c..03478a113 100644 --- a/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt +++ b/profile/profile-ports/profile-postgres/src/main/kotlin/co/nilin/opex/profile/ports/postgres/dao/ProfileApprovalRequestRepository.kt @@ -77,7 +77,7 @@ interface ProfileApprovalRequestRepository : ReactiveCrudRepository + ): Flow @Query("select * from profile_approval_request p where p.user_id = :userId order by create_date desc limit 1") fun findByUserId(userId: String): Mono From 26ce19b47a90eab0616e2349e0b31e0ff90532df Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Wed, 20 May 2026 19:29:11 +0330 Subject: [PATCH 33/56] Update swagger data about storage and swap services --- .../opex/controller/StorageAdminController.kt | 167 +++++++++++++----- .../opex/controller/StorageController.kt | 27 ++- .../ports/opex/controller/SwapController.kt | 43 ++++- 3 files changed, 188 insertions(+), 49 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt index 18dded9a0..419ae8edb 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt @@ -3,24 +3,36 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.spi.StorageProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import org.springframework.beans.factory.annotation.Value +import org.springframework.http.ResponseEntity +import org.springframework.http.codec.multipart.FilePart +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.beans.factory.annotation.Value -import org.springframework.http.ResponseEntity -import org.springframework.http.codec.multipart.FilePart -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* +import org.springframework.http.MediaType + + +@Schema(name = "StorageUploadMultipartRequest") +data class StorageUploadMultipartRequest( + + @field:Schema( + description = "File to upload.", + type = "string", + format = "binary" + ) + val file: String? = null +) @RestController @RequestMapping("/opex/v1/admin/storage") -@Tag(name = "Storage Admin", description = "Admin operations for storage service") +@Tag(name = "Storage Admin", description = "Admin storage upload, download, and delete operations.\n\nAllowed values:\n- isPublic: true, false.") class StorageAdminController( private val storageProxy: StorageProxy, @Value("\${app.base.url}") @@ -28,76 +40,143 @@ class StorageAdminController( ) { @GetMapping @Operation( - summary = "Admin: download file", - description = "Download a file by bucket and key.", + summary = "Download", + description = """GET /opex/v1/admin/storage. +Behavior: Returns binary file bytes for the requested bucket/key. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "bucket", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), - Parameter(name = "key", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")) - ], responses = [ - ApiResponse( - responseCode = "200", - description = "OK", - content = [Content(mediaType = "application/octet-stream", schema = Schema(type = "string", format = "binary"))] - ) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/octet-stream", schema = Schema(type = "string", format = "binary"))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun download( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "bucket", description = "Storage bucket name.", required = true) @RequestParam("bucket") bucket: String, - @RequestParam("key") key: String, + @Parameter(name = "key", description = "Storage object key.", required = true) + @RequestParam("key") key: String ): ResponseEntity { return storageProxy.adminDownload(securityContext.jwtAuthentication().tokenValue(), bucket, key) } - @PostMapping + @PostMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) @Operation( - summary = "Admin: upload file", - description = "Upload a file to a bucket with a specific key.", + summary = "Upload", + description = """POST /opex/v1/admin/storage. +Behavior: Multipart upload. `file` is required. `isPublic` defaults to false when omitted. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Validation: Send multipart/form-data with a `file` part. `bucket` and `key` identify the target object. +Allowed values: +- isPublic: true, false.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "bucket", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), - Parameter(name = "key", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), - Parameter(name = "isPublic", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "boolean")) - ], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [ + Content( + mediaType = MediaType.MULTIPART_FORM_DATA_VALUE, + schema = Schema(implementation = StorageUploadMultipartRequest::class) + ) + ] + ), responses = [ ApiResponse( responseCode = "200", - description = "OK", - content = [Content(mediaType = "text/plain", schema = Schema(type = "string"))] + description = "Successful response.", + content = [ + Content( + mediaType = "text/plain", + schema = Schema(type = "string") + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] ) ] ) + suspend fun upload( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestParam("bucket") bucket: String, - @RequestParam("key") key: String, - @RequestPart("file") file: FilePart, - @RequestParam("isPublic") isPublic: Boolean? = false, + + @Parameter( + name = "bucket", + description = "Storage bucket name.", + required = true + ) + @RequestParam("bucket") + bucket: String, + + @Parameter( + name = "key", + description = "Storage object key.", + required = true + ) + @RequestParam("key") + key: String, + + @Parameter( + name = "file", + description = "File to upload.", + required = true, + schema = Schema(type = "string", format = "binary") + ) + @RequestPart("file") + file: FilePart, + + @Parameter( + name = "isPublic", + description = "Whether the uploaded object should be publicly accessible.", + required = false, + schema = Schema(type = "boolean", defaultValue = "false") + ) + @RequestParam("isPublic", required = false) + isPublic: Boolean? = false ): String { - storageProxy.adminUpload(securityContext.jwtAuthentication().tokenValue(), bucket, key, file, isPublic) + storageProxy.adminUpload( + securityContext.jwtAuthentication().tokenValue(), + bucket, + key, + file, + isPublic + ) return "$appBaseUrl/opex/v1/storage?bucket=$bucket&key=$key" } @DeleteMapping @Operation( - summary = "Admin: delete file", - description = "Delete a file by bucket and key.", + summary = "Delete", + description = """DELETE /opex/v1/admin/storage. +Behavior: Deletes the object identified by bucket/key. Response has no body. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "bucket", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), - Parameter(name = "key", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")) - ], responses = [ - ApiResponse(responseCode = "200", description = "Deleted") + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun delete( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "bucket", description = "Storage bucket name.", required = true) @RequestParam("bucket") bucket: String, - @RequestParam("key") key: String, + @Parameter(name = "key", description = "Storage object key.", required = true) + @RequestParam("key") key: String ) { storageProxy.adminDelete(securityContext.jwtAuthentication().tokenValue(), bucket, key) } -} \ No newline at end of file +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt index dd532ded9..70e056fe5 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt @@ -6,18 +6,39 @@ import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/storage") +@Tag(name = "Storage", description = "Public storage download operations.") class StorageController( - private val storageProxy: StorageProxy, + private val storageProxy: StorageProxy ) { @GetMapping + @Operation( + summary = "Download", + description = """GET /opex/v1/storage. +Behavior: Public file download for the requested bucket/key. Returns binary file bytes. +Security: Public endpoint. No Bearer token is required. +""", + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/octet-stream", schema = Schema(type = "string", format = "binary"))]) + ] + ) suspend fun download( + @Parameter(name = "bucket", description = "Storage bucket name.", required = true) @RequestParam("bucket") bucket: String, - @RequestParam("key") key: String, + @Parameter(name = "key", description = "Storage object key.", required = true) + @RequestParam("key") key: String ): ResponseEntity { return storageProxy.publicDownload(bucket, key) } -} \ No newline at end of file +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt index 29330c9dd..9214d41a8 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt @@ -9,25 +9,64 @@ import co.nilin.opex.api.ports.opex.util.tokenValue import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/swap") +@Tag(name = "Swap", description = "Authenticated swap reserve and finalize operations.\n\nAllowed values:\n- sourceWalletType and destWalletType where used: MAIN, EXCHANGE, CASHOUT.\nSource of values:\n- sourceSymbol and destSymbol are server-provided currency symbols.") class SwapController( - val walletProxy: WalletProxy, + val walletProxy: WalletProxy ) { @PostMapping("/reserve") + @Operation( + summary = "Reserve", + description = """POST /opex/v1/swap/reserve. +Security: Bearer user-token required. Requires authenticated user JWT. +Source of values: +- sourceSymbol and destSymbol are server-provided currency symbols.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ReservedTransferResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun reserve( @RequestBody request: TransferReserveRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): ReservedTransferResponse { return walletProxy.reserveSwap(securityContext.jwtAuthentication().tokenValue(), request) } @PostMapping("/finalize/{reserveUuid}") + @Operation( + summary = "Finalize transfer", + description = """POST /opex/v1/swap/finalize/{reserveUuid}. +Behavior: `description` and `transferRef` are optional metadata for finalizing a reserved swap. +Security: Bearer user-token required. Requires authenticated user JWT. +Source of values: +- sourceSymbol and destSymbol are server-provided currency symbols.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun finalizeTransfer( + @Parameter(name = "reserveUuid", description = "Swap reserve UUID returned by reserve endpoint.", required = true) @PathVariable reserveUuid: String, + @Parameter(name = "description", description = "Optional transfer description.", required = false) @RequestParam description: String?, + @Parameter(name = "transferRef", description = "Optional external transfer reference.", required = false) @RequestParam transferRef: String?, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): TransferResult { return walletProxy.finalizeSwap( @@ -37,4 +76,4 @@ class SwapController( transferRef ) } -} \ No newline at end of file +} From 63f678e6bfa003e47f20b44042145f61440b0c58 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Wed, 20 May 2026 21:28:48 +0330 Subject: [PATCH 34/56] Consider separated request body for swap history --- .../core/inout/UserSwapTransactionRequest.kt | 18 ++ .../api/core/inout/UserTransactionRequest.kt | 4 - .../co/nilin/opex/api/core/spi/WalletProxy.kt | 2 +- .../opex/controller/ProfileAdminController.kt | 131 +++++++++++--- .../opex/controller/StorageAdminController.kt | 2 +- .../ports/opex/controller/SwapController.kt | 2 +- .../controller/TerminalAdminController.kt | 136 +++++++++++++- .../controller/TransactionAdminController.kt | 169 +++++++++++++++++- .../api/ports/proxy/impl/WalletProxyImpl.kt | 3 +- .../AdvancedTransferAdminController.kt | 4 +- .../controller/AdvancedTransferController.kt | 5 +- .../app/dto/UserSwapTransactionRequest.kt | 18 ++ .../wallet/app/dto/UserTransactionRequest.kt | 4 +- 13 files changed, 451 insertions(+), 47 deletions(-) create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt create mode 100644 wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserSwapTransactionRequest.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt new file mode 100644 index 000000000..b8b8f368e --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt @@ -0,0 +1,18 @@ +package co.nilin.opex.api.core.inout + +data class UserSwapTransactionRequest( + val userId: String? = null, + val currency: String?, + val sourceSymbol: String?, + val destSymbol: String?, + val startTime: Long? = null, + val endTime: Long? = null, + val limit: Int? = 10, + val offset: Int? = 0, + val ascendingByTime: Boolean = false, + val status: ReservedStatus? = ReservedStatus.Committed +) + +enum class ReservedStatus { + Created, Expired, Committed, +} \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserTransactionRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserTransactionRequest.kt index 814642140..898d4c420 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserTransactionRequest.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserTransactionRequest.kt @@ -11,9 +11,5 @@ data class UserTransactionRequest( val limit: Int? = 10, val offset: Int? = 0, val ascendingByTime: Boolean = false, - val status: ReservedStatus? = ReservedStatus.Committed ) -enum class ReservedStatus { - Created, Expired, Committed, -} \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index 2614594fd..a72bc5377 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -147,7 +147,7 @@ interface WalletProxy { suspend fun getSwapTransactionsForAdmin( token: String, - request: UserTransactionRequest + request: UserSwapTransactionRequest ): List suspend fun getTradeHistoryForAdmin( diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt index 8753429c8..41463a4d3 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt @@ -18,7 +18,7 @@ import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/profile") -@Tag(name = "Profile Admin", description = "Admin profile and approval request operations.\n\nAllowed values:\n- nationality: IRANIAN, NON_IRANIAN.\n- gender: FEMALE, MALE.\n- status: CREATED, CONTACT_INFO_COMPLETED, PROFILE_COMPLETED, SYSTEM_APPROVED, PENDING_ADMIN_APPROVAL, ADMIN_REJECTED, ADMIN_APPROVED.\n- kycLevel: LEVEL_1, LEVEL_2, LEVEL_3.\n- approval request status: PENDING, APPROVED, REJECTED.") +@Tag(name = "Profile Admin", description = "Admin profile and approval request operations.") class ProfileAdminController(private val profileProxy: ProfileProxy) { @PostMapping @@ -34,9 +34,24 @@ Allowed values: - approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = Profile::class)))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = Profile::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getProfiles( @@ -63,13 +78,29 @@ Allowed values: - approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = Profile::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = Profile::class))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getProfile( - @Parameter(name = "uuid", description = "User/profile/terminal UUID depending on the endpoint context.", required = true) + @Parameter( + name = "uuid", + description = "User/profile/terminal UUID depending on the endpoint context.", + required = true + ) @PathVariable uuid: String, @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext @@ -91,9 +122,24 @@ Allowed values: - approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = ProfileHistory::class)))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = ProfileHistory::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getProfileHistory( @@ -127,9 +173,24 @@ Allowed values: - approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = ProfileApprovalAdminResponse::class)))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = ProfileApprovalAdminResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getApprovalRequests( @@ -153,9 +214,24 @@ Allowed values: - approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileApprovalAdminResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ProfileApprovalAdminResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getApprovalRequest( @@ -180,9 +256,24 @@ Allowed values: - approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileApprovalAdminResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ProfileApprovalAdminResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun updateApprovalRequestStatus( diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt index 419ae8edb..49ec65e6e 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt @@ -32,7 +32,7 @@ data class StorageUploadMultipartRequest( @RestController @RequestMapping("/opex/v1/admin/storage") -@Tag(name = "Storage Admin", description = "Admin storage upload, download, and delete operations.\n\nAllowed values:\n- isPublic: true, false.") +@Tag(name = "Storage Admin", description = "Admin storage upload, download, and delete operations.") class StorageAdminController( private val storageProxy: StorageProxy, @Value("\${app.base.url}") diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt index 9214d41a8..b26e6cbbe 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt @@ -20,7 +20,7 @@ import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/swap") -@Tag(name = "Swap", description = "Authenticated swap reserve and finalize operations.\n\nAllowed values:\n- sourceWalletType and destWalletType where used: MAIN, EXCHANGE, CASHOUT.\nSource of values:\n- sourceSymbol and destSymbol are server-provided currency symbols.") +@Tag(name = "Swap", description = "Authenticated swap reserve and finalize operations.") class SwapController( val walletProxy: WalletProxy ) { diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt index 932733f64..a189b4555 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt @@ -8,14 +8,36 @@ import co.nilin.opex.api.ports.opex.util.tokenValue import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/terminal") +@Tag(name = "Terminal Admin", description = "Admin terminal and terminal-gateway assignment operations.") class TerminalAdminController( - private val walletProxy: WalletProxy, + private val walletProxy: WalletProxy ) { @PostMapping + @Operation( + summary = "Register terminal", + description = """POST /opex/v1/admin/terminal. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalCommand::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun registerTerminal( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody body: TerminalCommand ): TerminalCommand? { return walletProxy.saveTerminal(securityContext.jwtAuthentication().tokenValue(), body) @@ -23,8 +45,22 @@ class TerminalAdminController( @PutMapping("/{uuid}") + @Operation( + summary = "Update terminal", + description = """PUT /opex/v1/admin/terminal/{uuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalCommand::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun updateTerminal( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "uuid", description = "Terminal UUID.", required = true) @PathVariable("uuid") terminalUuid: String, @RequestBody body: TerminalCommand ): TerminalCommand? { @@ -32,41 +68,112 @@ class TerminalAdminController( } @DeleteMapping("/{uuid}") + @Operation( + summary = "Delete terminal", + description = """DELETE /opex/v1/admin/terminal/{uuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun deleteTerminal( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @PathVariable("uuid") terminalUuid: String, + @Parameter(name = "uuid", description = "Terminal UUID.", required = true) + @PathVariable("uuid") terminalUuid: String ) { walletProxy.deleteTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) } @GetMapping + @Operation( + summary = "Get terminal", + description = """GET /opex/v1/admin/terminal. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getTerminal( - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List? { return walletProxy.getTerminals(securityContext.jwtAuthentication().tokenValue()) } @GetMapping("/{uuid}") + @Operation( + summary = "Get terminal", + description = """GET /opex/v1/admin/terminal/{uuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalCommand::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getTerminal( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @PathVariable("uuid") terminalUuid: String, + @Parameter(name = "uuid", description = "User/profile/terminal UUID depending on the endpoint context.", required = true) + @PathVariable("uuid") terminalUuid: String ): TerminalCommand? { return walletProxy.getTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) } @GetMapping("/{uuid}/gateway") + @Operation( + summary = "Get gateway(s) which the terminal is assigned to", + description = """GET /opex/v1/admin/terminal/{uuid}/gateway. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun getGatewayTerminal( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @PathVariable("uuid") terminalUuid: String, + @Parameter(name = "uuid", description = "Terminal UUID.", required = true) + @PathVariable("uuid") terminalUuid: String ): List? { return walletProxy.getAssignedGatewayToTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) } @PostMapping("/gateway/{uuid}") + @Operation( + summary = "Assign terminal to gateway", + description = """POST /opex/v1/admin/terminal/gateway/{uuid}. +Validation: Request body is a raw JSON array of terminal UUID strings. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun assignTerminalToGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "uuid", description = "Gateway UUID.", required = true) @PathVariable("uuid") gatewayUuid: String, - @RequestBody terminal: List, + @RequestBody terminal: List ) { return walletProxy.assignTerminalsToGateway( securityContext.jwtAuthentication().tokenValue(), @@ -76,10 +183,25 @@ class TerminalAdminController( } @DeleteMapping("/gateway/{uuid}") + @Operation( + summary = "Revoke terminal from gateway", + description = """DELETE /opex/v1/admin/terminal/gateway/{uuid}. +Validation: Request body is a raw JSON array of terminal UUID strings to revoke from the gateway. +Security: Bearer admin-token required. Required authority: ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun revokeTerminalFromGateway( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "uuid", description = "Gateway UUID.", required = true) @PathVariable("uuid") gatewayUuid: String, - @RequestBody terminal: List, + @RequestBody terminal: List ) { return walletProxy.revokeTerminalsToGateway( securityContext.jwtAuthentication().tokenValue(), diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt index c55f72079..d2d86bcd2 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt @@ -10,24 +10,96 @@ import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/transactions") +@Tag(name = "Transactions Admin", description = "Admin transaction history and summary operations.") class TransactionAdminController( - private val walletProxy: WalletProxy, + private val walletProxy: WalletProxy ) { @PostMapping("/summary") + @Operation( + summary = "Get user transaction history", + description = """POST /opex/v1/admin/transactions/summary. +Security: Bearer admin-token required. Required authority: ROLE_monitoring or ROLE_admin. +Allowed values: +- category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM. +- ReservedStatus: Created, Expired, Committed + +""", + + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = UserTransactionHistory::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_monitoring or ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun getUserTransactionHistory( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UserTransactionRequest, + @RequestBody request: UserTransactionRequest ): List { return walletProxy.getUserTransactionHistoryForAdmin(securityContext.jwtAuthentication().tokenValue(), request) } @PostMapping("/deposits") + @Operation( + summary = "Get deposit transactions", + description = """POST /opex/v1/admin/transactions/deposits. +Security: Bearer admin-token required. Required authority: ROLE_monitoring or ROLE_admin. +Allowed values: +- DepositStatus: PROCESSING, DONE, INVALID +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = DepositAdminResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_monitoring or ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun getDepositTransactions( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody request: AdminDepositHistoryRequest ): List { @@ -38,7 +110,36 @@ class TransactionAdminController( } @PostMapping("/withdraws") + @Operation( + summary = "Get withdraw transactions", + description = """POST /opex/v1/admin/transactions/withdraws. +Security: Bearer admin-token required. Required authority: ROLE_monitoring or ROLE_admin. +Allowed values: +- category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = WithdrawAdminResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_monitoring or ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun getWithdrawTransactions( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody request: AdminWithdrawHistoryRequest ): List { @@ -49,9 +150,39 @@ class TransactionAdminController( } @PostMapping("/swaps") + @Operation( + summary = "Get swap transactions", + description = """POST /opex/v1/admin/transactions/swaps. +Security: Bearer admin-token required. Required authority: ROLE_monitoring or ROLE_admin. +Allowed values: +- ReservedStatus: Created, Expired, Committed, +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = SwapAdminResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_monitoring or ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun getSwapTransactions( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UserTransactionRequest, + @RequestBody request: UserSwapTransactionRequest ): List { return walletProxy.getSwapTransactionsForAdmin( securityContext.jwtAuthentication().tokenValue(), @@ -61,10 +192,38 @@ class TransactionAdminController( // This part is temporary and the structure of fetching trades needs to be fixed. @PostMapping("/trades") + @Operation( + summary = "Get transaction history", + description = """POST /opex/v1/admin/transactions/trades. +Security: Bearer admin-token required. Required authority: ROLE_monitoring or ROLE_admin. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TradeAdminResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_monitoring or ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun getTransactionHistory( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: AdminTradeHistoryRequest, + @RequestBody request: AdminTradeHistoryRequest ): List { return walletProxy.getTradeHistoryForAdmin(securityContext.jwtAuthentication().tokenValue(), request) } -} \ No newline at end of file +} diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index 6e8c6db25..d3f10c0b5 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -207,7 +207,6 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC limit, offset, ascendingByTime == true, - null ) ) ) @@ -515,7 +514,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC override suspend fun getSwapTransactionsForAdmin( token: String, - request: UserTransactionRequest + request: UserSwapTransactionRequest ): List { return webClient.post() .uri("$baseUrl/admin/v1/swap/history") diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferAdminController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferAdminController.kt index 97dfba756..703419083 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferAdminController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferAdminController.kt @@ -1,5 +1,6 @@ package co.nilin.opex.wallet.app.controller +import co.nilin.opex.wallet.app.dto.UserSwapTransactionRequest import co.nilin.opex.wallet.app.dto.UserTransactionRequest import co.nilin.opex.wallet.core.inout.AdminSwapResponse import co.nilin.opex.wallet.core.spi.ReservedTransferManager @@ -35,8 +36,7 @@ class AdvancedTransferAdminController { ) ) suspend fun getSwapHistory( - @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UserTransactionRequest + @RequestBody request: UserSwapTransactionRequest ): List? { return with(request) { diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt index e3ef85e7b..0d9016edd 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/AdvancedTransferController.kt @@ -4,6 +4,7 @@ import co.nilin.opex.common.OpexError import co.nilin.opex.wallet.app.dto.ReservedTransferResponse import co.nilin.opex.wallet.app.dto.TransferPreEvaluateResponse import co.nilin.opex.wallet.app.dto.TransferReserveRequest +import co.nilin.opex.wallet.app.dto.UserSwapTransactionRequest import co.nilin.opex.wallet.app.dto.UserTransactionRequest import co.nilin.opex.wallet.app.service.TransferService import co.nilin.opex.wallet.core.inout.SwapResponse @@ -140,7 +141,7 @@ class AdvancedTransferController { ) suspend fun getSwapHistory( @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UserTransactionRequest + @RequestBody request: UserSwapTransactionRequest ): List? { return with(request) { @@ -171,7 +172,7 @@ class AdvancedTransferController { @PostMapping("/v1/swap/history/count") suspend fun getSwapHistoryCount( @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UserTransactionRequest + @RequestBody request: UserSwapTransactionRequest ): Long { return with(request) { diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserSwapTransactionRequest.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserSwapTransactionRequest.kt new file mode 100644 index 000000000..20a0a2335 --- /dev/null +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserSwapTransactionRequest.kt @@ -0,0 +1,18 @@ +package co.nilin.opex.wallet.app.dto + +import co.nilin.opex.wallet.core.model.UserTransactionCategory +import co.nilin.opex.wallet.core.model.otc.ReservedStatus + +data class UserSwapTransactionRequest( + val userId: String? = null, + val currency: String?, + val sourceSymbol: String?, + val destSymbol: String?, + val startTime: Long? = null, + val endTime: Long? = null, + val limit: Int? = 10, + val offset: Int? = 0, + val ascendingByTime: Boolean = false, + val status: ReservedStatus? = ReservedStatus.Committed +) + diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserTransactionRequest.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserTransactionRequest.kt index df18304bf..d491efc0c 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserTransactionRequest.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/dto/UserTransactionRequest.kt @@ -14,5 +14,5 @@ data class UserTransactionRequest( val limit: Int? = 10, val offset: Int? = 0, val ascendingByTime: Boolean = false, - val status: ReservedStatus? = ReservedStatus.Committed -) \ No newline at end of file +) + From 0fdabfe902ee4f9e75023118f6e41a6fedb945bf Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sun, 24 May 2026 18:01:00 +0330 Subject: [PATCH 35/56] Update swagger data about admin terminal controller --- .../opex/api/core/inout/GatewayCommand.kt | 3 - .../api/core/inout/GatewayUpdateCommand.kt | 105 ++++++++++++++++++ .../opex/api/core/inout/TerminalCommand.kt | 9 +- .../api/core/inout/TerminalUpdateCommand.kt | 9 ++ .../co/nilin/opex/api/core/spi/WalletProxy.kt | 4 +- .../opex/controller/GatewayAdminController.kt | 3 +- .../controller/TerminalAdminController.kt | 17 +-- .../api/ports/proxy/impl/WalletProxyImpl.kt | 22 ++-- .../app/controller/TerminalAdminController.kt | 98 ++++++++++++++++ .../postgres/impl/TerminalManagerImpl.kt | 8 +- 10 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayUpdateCommand.kt create mode 100644 api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalUpdateCommand.kt create mode 100644 wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TerminalAdminController.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayCommand.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayCommand.kt index 65b52c913..457deb99a 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayCommand.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayCommand.kt @@ -5,9 +5,6 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo import java.math.BigDecimal import java.util.* -enum class GatewayType() { - OnChain, OffChain -} @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayUpdateCommand.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayUpdateCommand.kt new file mode 100644 index 000000000..6378b2c25 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/GatewayUpdateCommand.kt @@ -0,0 +1,105 @@ +package co.nilin.opex.api.core.inout + +import com.fasterxml.jackson.annotation.JsonSubTypes +import com.fasterxml.jackson.annotation.JsonTypeInfo +import java.math.BigDecimal +import java.util.* + +enum class GatewayType() { + OnChain, OffChain +} + +@JsonTypeInfo( + use = JsonTypeInfo.Id.NAME, + include = JsonTypeInfo.As.PROPERTY, + property = "type" +) +@JsonSubTypes( + JsonSubTypes.Type(value = OffChainGatewayCommand::class, name = "OffChain"), + JsonSubTypes.Type(value = OnChainGatewayCommand::class, name = "OnChain"), +) +open abstract class CurrencyGatewayUpdateCommand( + open var currencySymbol: String? = null, + open var gatewayUuid: String? = UUID.randomUUID().toString(), + open var isDepositActive: Boolean?, + open var isWithdrawActive: Boolean?, + open var withdrawFee: BigDecimal? = BigDecimal.ZERO, + open var withdrawAllowed: Boolean? = true, + open var depositAllowed: Boolean? = true, + open var depositMin: BigDecimal? = BigDecimal.ZERO, + open var depositMax: BigDecimal? = BigDecimal.ZERO, + open var withdrawMin: BigDecimal? = BigDecimal.ZERO, + open var withdrawMax: BigDecimal? = BigDecimal.ZERO, + open var displayOrder: Int? = null, +) + +data class OffChainGatewayUpdateCommand( + var transferMethod: TransferMethod, + override var currencySymbol: String? = null, + override var gatewayUuid: String? = UUID.randomUUID().toString(), + override var isDepositActive: Boolean? = true, + override var isWithdrawActive: Boolean? = true, + override var withdrawFee: BigDecimal? = BigDecimal.ZERO, + override var withdrawAllowed: Boolean? = true, + override var depositAllowed: Boolean? = true, + override var depositMin: BigDecimal? = BigDecimal.ZERO, + override var depositMax: BigDecimal? = BigDecimal.ZERO, + override var withdrawMin: BigDecimal? = BigDecimal.ZERO, + override var withdrawMax: BigDecimal? = BigDecimal.ZERO, + override var displayOrder: Int? = null, + + ) : CurrencyGatewayCommand( + currencySymbol, + gatewayUuid, + isDepositActive, + isWithdrawActive, + withdrawFee, + withdrawAllowed, + depositAllowed, + depositMin, + depositMax, + withdrawMin, + withdrawMax, + null, + null, + displayOrder +) + +data class OnChainGatewayUpdateCommand( + + var implementationSymbol: String? = null, + var tokenName: String? = null, + var tokenAddress: String? = null, + var isToken: Boolean? = false, + var decimal: Int, + var chain: String, + override var currencySymbol: String? = null, + override var gatewayUuid: String? = UUID.randomUUID().toString(), + override var isDepositActive: Boolean? = true, + override var isWithdrawActive: Boolean? = true, + override var withdrawFee: BigDecimal? = BigDecimal.ZERO, + override var withdrawAllowed: Boolean? = true, + override var depositAllowed: Boolean? = true, + override var depositMin: BigDecimal? = BigDecimal.ZERO, + override var depositMax: BigDecimal? = BigDecimal.ZERO, + override var withdrawMin: BigDecimal? = BigDecimal.ZERO, + override var withdrawMax: BigDecimal? = BigDecimal.ZERO, + override var displayOrder: Int? = null, +) : CurrencyGatewayCommand( + currencySymbol, + gatewayUuid, + isDepositActive, + isWithdrawActive, + withdrawFee, + withdrawAllowed, + depositAllowed, + depositMin, + depositMax, + withdrawMin, + withdrawMax, + null, + null, + displayOrder +) + + diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt index a7c919deb..5439e9feb 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalCommand.kt @@ -1,12 +1,11 @@ package co.nilin.opex.api.core.inout -data class TerminalCommand( +data class TerminalCommand( var uuid: String?, - var owner: String?=null, + var owner: String? = null, var identifier: String, var active: Boolean? = true, var metaData: String, - var description : String?=null, + var description: String? = null, var displayOrder: Int? = null, - -) + ) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalUpdateCommand.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalUpdateCommand.kt new file mode 100644 index 000000000..c77b1a668 --- /dev/null +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/TerminalUpdateCommand.kt @@ -0,0 +1,9 @@ +package co.nilin.opex.api.core.inout + +data class TerminalUpdateCommand( + var uuid: String?, + var identifier: String, + var active: Boolean? = true, + var metaData: String, + var displayOrder: Int? = null, + ) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index a72bc5377..41a3dd1b5 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -234,7 +234,7 @@ interface WalletProxy { suspend fun deleteOffChainGatewayLocalization(token: String, id: Long) suspend fun saveTerminal(token: String, terminal: TerminalCommand): TerminalCommand? - suspend fun updateTerminal(token: String, terminalUuid: String, terminal: TerminalCommand): TerminalCommand? + suspend fun updateTerminal(token: String, terminalUuid: String, terminal: TerminalUpdateCommand): TerminalCommand? suspend fun deleteTerminal(token: String, terminalUuid: String) suspend fun getTerminals(token: String): List? suspend fun getTerminal(token: String, terminalUuid: String): TerminalCommand? @@ -251,7 +251,7 @@ interface WalletProxy { token: String, gatewayUuid: String, currencySymbol: String, - gatewayCommand: CurrencyGatewayCommand + gatewayCommand: CurrencyGatewayUpdateCommand ): CurrencyGatewayCommand? suspend fun getGateway(token: String, gatewayUuid: String, currencySymbol: String): CurrencyGatewayCommand? diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt index 3022d027b..83c16767e 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt @@ -1,6 +1,7 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.CurrencyGatewayCommand +import co.nilin.opex.api.core.inout.CurrencyGatewayUpdateCommand import co.nilin.opex.api.core.inout.OffChainGatewayCommand import co.nilin.opex.api.core.inout.OnChainGatewayCommand import co.nilin.opex.api.core.spi.WalletProxy @@ -359,7 +360,7 @@ Response body: CurrencyGatewayCommand. @CurrentSecurityContext securityContext: SecurityContext, @PathVariable("uuid") gatewayUuid: String, @PathVariable("currencySymbol") currencySymbol: String, - @RequestBody body: CurrencyGatewayCommand, + @RequestBody body: CurrencyGatewayUpdateCommand, ): CurrencyGatewayCommand? { return walletProxy.updateGateway( securityContext.jwtAuthentication().tokenValue(), diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt index a189b4555..905e23bce 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt @@ -2,6 +2,7 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.CurrencyGatewayCommand import co.nilin.opex.api.core.inout.TerminalCommand +import co.nilin.opex.api.core.inout.TerminalUpdateCommand import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue @@ -47,7 +48,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. @PutMapping("/{uuid}") @Operation( summary = "Update terminal", - description = """PUT /opex/v1/admin/terminal/{uuid}. + description = """PUT /opex/v1/admin/terminal/{terminalUuid}. Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], @@ -62,7 +63,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. @CurrentSecurityContext securityContext: SecurityContext, @Parameter(name = "uuid", description = "Terminal UUID.", required = true) @PathVariable("uuid") terminalUuid: String, - @RequestBody body: TerminalCommand + @RequestBody body: TerminalUpdateCommand ): TerminalCommand? { return walletProxy.updateTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid, body) } @@ -70,7 +71,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. @DeleteMapping("/{uuid}") @Operation( summary = "Delete terminal", - description = """DELETE /opex/v1/admin/terminal/{uuid}. + description = """DELETE /opex/v1/admin/terminal/{terminalUuid}. Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], @@ -112,7 +113,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. @GetMapping("/{uuid}") @Operation( summary = "Get terminal", - description = """GET /opex/v1/admin/terminal/{uuid}. + description = """GET /opex/v1/admin/terminal/{terminalUuid}. Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], @@ -125,7 +126,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. suspend fun getTerminal( @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @Parameter(name = "uuid", description = "User/profile/terminal UUID depending on the endpoint context.", required = true) + @Parameter(name = "uuid", description = "Terminal UUID depending on the endpoint context.", required = true) @PathVariable("uuid") terminalUuid: String ): TerminalCommand? { return walletProxy.getTerminal(securityContext.jwtAuthentication().tokenValue(), terminalUuid) @@ -134,7 +135,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. @GetMapping("/{uuid}/gateway") @Operation( summary = "Get gateway(s) which the terminal is assigned to", - description = """GET /opex/v1/admin/terminal/{uuid}/gateway. + description = """GET /opex/v1/admin/terminal/{gatewayUuid}/gateway. Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], @@ -156,7 +157,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. @PostMapping("/gateway/{uuid}") @Operation( summary = "Assign terminal to gateway", - description = """POST /opex/v1/admin/terminal/gateway/{uuid}. + description = """POST /opex/v1/admin/terminal/gateway/{gatewayUuid}. Validation: Request body is a raw JSON array of terminal UUID strings. Security: Bearer admin-token required. Required authority: ROLE_admin. @@ -185,7 +186,7 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. @DeleteMapping("/gateway/{uuid}") @Operation( summary = "Revoke terminal from gateway", - description = """DELETE /opex/v1/admin/terminal/gateway/{uuid}. + description = """DELETE /opex/v1/admin/terminal/gateway/{gatewayUuid}. Validation: Request body is a raw JSON array of terminal UUID strings to revoke from the gateway. Security: Bearer admin-token required. Required authority: ROLE_admin. """, diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index d3f10c0b5..c37c30936 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -829,7 +829,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC terminalUuid: String ): TerminalLocalizationResponse { return webClient.get() - .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}/localization") + .uri("$baseUrl/admin/terminal/${terminalUuid}/localization") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() @@ -844,7 +844,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC terminalLocalizations: List ): TerminalLocalizationResponse { return webClient.post() - .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}/localization") + .uri("$baseUrl/admin/terminal/${terminalUuid}/localization") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .body(Mono.just(terminalLocalizations)) @@ -856,7 +856,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC override suspend fun deleteTerminalLocalization(token: String, id: Long) { webClient.delete() - .uri("$baseUrl/admin/deposit/terminal/localization/${id}") + .uri("$baseUrl/admin/terminal/localization/${id}") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() @@ -913,7 +913,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC terminal: TerminalCommand ): TerminalCommand? { return webClient.post() - .uri("$baseUrl/admin/deposit/terminal") + .uri("$baseUrl/admin/terminal") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .body(Mono.just(terminal)) @@ -926,10 +926,10 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC override suspend fun updateTerminal( token: String, terminalUuid: String, - terminal: TerminalCommand + terminal: TerminalUpdateCommand ): TerminalCommand? { return webClient.put() - .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}") + .uri("$baseUrl/admin/terminal/${terminalUuid}") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .body(Mono.just(terminal)) @@ -941,7 +941,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC override suspend fun deleteTerminal(token: String, terminalUuid: String) { webClient.delete() - .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}") + .uri("$baseUrl/admin/terminal/${terminalUuid}") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() @@ -968,13 +968,13 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC terminalUuid: String ): TerminalCommand? { return webClient.get() - .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}") + .uri("$baseUrl/admin/terminal/${terminalUuid}") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() .onStatus({ t -> t.isError }, { it.createException() }) .bodyToMono() - .awaitFirstOrElse { throw OpexError.BadRequest.exception() } + .awaitFirstOrElse { throw OpexError.NotFound.exception() } } override suspend fun getAssignedGatewayToTerminal( @@ -982,7 +982,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC terminalUuid: String ): List? { return webClient.get() - .uri("$baseUrl/admin/deposit/terminal/${terminalUuid}/gateway") + .uri("$baseUrl/admin/terminal/${terminalUuid}/gateway") .accept(MediaType.APPLICATION_JSON) .header(HttpHeaders.AUTHORIZATION, "Bearer $token") .retrieve() @@ -1046,7 +1046,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC token: String, gatewayUuid: String, currencySymbol: String, - gatewayCommand: CurrencyGatewayCommand + gatewayCommand: CurrencyGatewayUpdateCommand ): CurrencyGatewayCommand? { return webClient.put() .uri("$baseUrl/currency/${currencySymbol}/gateway/${gatewayUuid}") diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TerminalAdminController.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TerminalAdminController.kt new file mode 100644 index 000000000..9d8e9c06f --- /dev/null +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/controller/TerminalAdminController.kt @@ -0,0 +1,98 @@ +package co.nilin.opex.wallet.app.controller + +import co.nilin.opex.wallet.app.dto.AdminSearchDepositRequest +import co.nilin.opex.wallet.app.dto.ManualTransferRequest +import co.nilin.opex.wallet.app.dto.TerminalLocalizationResponse +import co.nilin.opex.wallet.app.service.DepositService +import co.nilin.opex.wallet.core.inout.* +import co.nilin.opex.wallet.core.spi.GatewayTerminalManager +import co.nilin.opex.wallet.core.spi.TerminalManager +import io.swagger.annotations.ApiResponse +import io.swagger.annotations.Example +import io.swagger.annotations.ExampleProperty +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* +import java.math.BigDecimal +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.* + +@RestController +@RequestMapping("/admin/terminal") + +class TerminalAdminController( + private val depositService: DepositService, + private val terminalManager: TerminalManager, + private val gatewayTerminalManager: GatewayTerminalManager +) { + + @PostMapping("") + suspend fun registerTerminal( + @RequestBody body: TerminalCommand + ): TerminalCommand? { + return terminalManager.save(body.apply { uuid = UUID.randomUUID().toString() }) + } + + + @PutMapping("/{uuid}") + suspend fun updateTerminal( + @PathVariable("uuid") terminalUuid: String, + @RequestBody body: TerminalCommand + ): TerminalCommand? { + return terminalManager.update(body.apply { uuid = terminalUuid }) + } + + + @DeleteMapping("/{uuid}") + suspend fun deleteTerminal( + @PathVariable("uuid") terminalUuid: String, + ) { + terminalManager.delete(terminalUuid) + } + + @GetMapping("") + suspend fun getTerminal( + ): List? { + return terminalManager.fetchTerminal() + } + + @GetMapping("/{uuid}") + suspend fun getTerminal( + @PathVariable("uuid") terminalUuid: String, + ): TerminalCommand? { + return terminalManager.fetchTerminal(terminalUuid) + } + + @GetMapping("/{uuid}/gateway") + suspend fun getGatewayTerminal( + @PathVariable("uuid") terminalUuid: String, + ): List? { + return gatewayTerminalManager.getAssignedGatewayToTerminal(terminalUuid) + } + + @PostMapping("/{uuid}/localization") + suspend fun saveTerminalLocalization( + @PathVariable("uuid") terminalUuid: String, + @RequestBody terminalLocalizations: List + ): TerminalLocalizationResponse { + val terminalLocalizations = terminalManager.saveTerminalLocalizations(terminalUuid, terminalLocalizations) + return TerminalLocalizationResponse(terminalUuid, terminalLocalizations) + } + + @GetMapping("/{uuid}/localization") + suspend fun getTerminalLocalization( + @PathVariable("uuid") terminalUuid: String + ): TerminalLocalizationResponse { + val terminalLocalizations = terminalManager.fetchTerminalLocalizations(terminalUuid) + return TerminalLocalizationResponse(terminalUuid, terminalLocalizations) + } + + @DeleteMapping("/terminal/localization/{id}") + suspend fun deleteTerminalLocalization( + @PathVariable("id") id: Long, + ) { + terminalManager.deleteTerminalLocalizations(id) + } +} \ No newline at end of file diff --git a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt index bc41de604..6da9be671 100644 --- a/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt +++ b/wallet/wallet-ports/wallet-persister-postgres/src/main/kotlin/co/nilin/opex/wallet/ports/postgres/impl/TerminalManagerImpl.kt @@ -68,9 +68,11 @@ class TerminalManagerImpl( } override suspend fun delete(uuid: String) { - loadTerminal(uuid)?.let { - terminalRepository.deleteById(it.id!!).awaitSingleOrNull() - } ?: throw OpexError.TerminalNotFound.exception() + val terminal = loadTerminal(uuid) + if (terminal != null) + terminalRepository.deleteById(terminal.id!!).awaitSingleOrNull() + else + throw OpexError.TerminalNotFound.exception() } override suspend fun fetchTerminal(): List? { From f133f544ec5712a805a8e61d0bc582ef63f3173f Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sun, 24 May 2026 20:30:40 +0330 Subject: [PATCH 36/56] Update swagger data about admin transactions controller --- .../api/ports/opex/controller/TransactionAdminController.kt | 4 +--- .../kotlin/co/nilin/opex/wallet/app/service/DepositService.kt | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt index d2d86bcd2..20ff066cc 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt @@ -34,7 +34,6 @@ class TransactionAdminController( Security: Bearer admin-token required. Required authority: ROLE_monitoring or ROLE_admin. Allowed values: - category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM. -- ReservedStatus: Created, Expired, Committed """, @@ -114,8 +113,7 @@ Allowed values: summary = "Get withdraw transactions", description = """POST /opex/v1/admin/transactions/withdraws. Security: Bearer admin-token required. Required authority: ROLE_monitoring or ROLE_admin. -Allowed values: -- category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( diff --git a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt index 33e688acf..86c96528d 100644 --- a/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt +++ b/wallet/wallet-app/src/main/kotlin/co/nilin/opex/wallet/app/service/DepositService.kt @@ -208,9 +208,9 @@ class DepositService( // ------------------------------------------------------------------------- fun isValidDeposit(deposit: Deposit, gatewayData: GatewayData): Boolean { - return gatewayData.isEnabled && + return deposit.transferMethod == TransferMethod.MANUALLY || (gatewayData.isEnabled && deposit.amount >= gatewayData.minimum && - deposit.amount <= gatewayData.maximum + deposit.amount <= gatewayData.maximum) } suspend fun fetchDepositData( From fd174268f6ad8de17bcb9a5d0b76bf1812b98de9 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 25 May 2026 18:12:33 +0330 Subject: [PATCH 37/56] Update swagger data about user exchange data --- .../core/inout/analytics/ActivityTotals.kt | 4 +- .../controller/UserAnalyticsController.kt | 83 ++++++++++- .../opex/controller/UserDataController.kt | 141 +++++++++++++----- .../opex/common/utils/LimitedInterval.kt | 32 ++++ 4 files changed, 218 insertions(+), 42 deletions(-) create mode 100644 common/src/main/kotlin/co/nilin/opex/common/utils/LimitedInterval.kt diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/analytics/ActivityTotals.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/analytics/ActivityTotals.kt index 43203da9d..11382715b 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/analytics/ActivityTotals.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/analytics/ActivityTotals.kt @@ -2,9 +2,7 @@ package co.nilin.opex.api.core.inout.analytics import java.math.BigDecimal -/** - * Totals for a single day of user activity (mock values for now). - */ + data class ActivityTotals( val totalBalance: BigDecimal, val totalWithdraw: BigDecimal, diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt index af11c880f..4d5d6433a 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt @@ -6,6 +6,15 @@ import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.service.UserActivityAggregationService import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.ExampleObject +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.GetMapping @@ -15,21 +24,89 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/analytics") +@Tag( + name = "User Analytics", + description = "User analytics and user-asset analytics operations." +) class UserAnalyticsController( private val userActivityAggregationService: UserActivityAggregationService, - val walletProxy: WalletProxy, + val walletProxy: WalletProxy ) { @GetMapping("/user-activity") - suspend fun userActivity(@CurrentSecurityContext securityContext: SecurityContext): Map { + @Operation( + summary = "User activity", + description = """GET /opex/v1/analytics/user-activity. +Security: Bearer user-token required. Requires authenticated user JWT. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [ + Content( + mediaType = "application/json", + schema = Schema( + type = "object", + additionalPropertiesSchema = ActivityTotals::class + ), + examples = [ + ExampleObject( + name = "User activity response", + value = """ +{ + "1715817600000": { + "totalBalance": 1200.00, + "totalWithdraw": 0, + "totalDeposit": 100.00, + "totalTrade": 300.00, + "totalOrder": 5 + } +} + """ + ) + ] + ) + ] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) + suspend fun userActivity( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ): Map { val auth = securityContext.jwtAuthentication() return userActivityAggregationService.getLast31DaysUserStats(auth.tokenValue(), auth.name) } @GetMapping("/users-detail-assets") + @Operation( + summary = "Get user details assets", + description = """GET /opex/v1/analytics/users-detail-assets. +Security: Public endpoint. No Bearer token is required. +""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = UserDetailAssetsSnapshot::class)) + )] + ) + ] + ) suspend fun getUserDetailsAssets( + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, - @RequestParam offset: Int?, + @Parameter(name = "offset", description = "Optional page offset.", required = false) + @RequestParam offset: Int? ): List { return walletProxy.getUsersDetailAssets(limit ?: 10, offset ?: 0) } diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt index 15e20a2e2..155570cfc 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserDataController.kt @@ -2,11 +2,10 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.inout.UserFee import co.nilin.opex.api.core.spi.AccountantProxy -import co.nilin.opex.common.OpexError import co.nilin.opex.common.utils.Interval +import co.nilin.opex.common.utils.LimitedInterval import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse @@ -22,81 +21,151 @@ import java.math.BigDecimal @RestController @RequestMapping("/opex/v1/user/data") -@Tag(name = "User Data", description = "Authenticated user data endpoints") +@Tag( + name = "User Exchange Data", + description = "Authenticated user fee, volume, and activity data." +) class UserDataController( - private val accountantProxy: AccountantProxy, + private val accountantProxy: AccountantProxy ) { @GetMapping("/trade/volume") @Operation( - summary = "Get user trade volume by currency", + summary = "Get trade volume by currency", + description = """GET /opex/v1/user/data/trade/volume. +Validation: `interval` must be one of Day, Week, Month, Year. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- interval: Day, Week, Month, Year.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "symbol", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")), - Parameter(name = "interval", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string", description = "Interval: Day|Week|Month|Year")) - ], - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(type = "number", format = "double")) ]) ] + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "number"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] ) suspend fun getTradeVolumeByCurrency( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter( + name = "symbol", + description = "Trading pair or currency symbol, depending on endpoint.", + required = true + ) @RequestParam symbol: String, - @RequestParam interval: Interval + @Parameter( + name = "interval", + description = "Interval. For user data endpoints allowed values are Day, Week, Month, Year. ", + required = true + ) + @RequestParam interval: LimitedInterval ): BigDecimal { - checkValidInterval(interval) + val interval = Interval.valueOf(interval.name) val uuid = securityContext.authentication.name return accountantProxy.getTradeVolumeByCurrency(uuid, symbol, interval) } @GetMapping("/trade/volume/total") @Operation( - summary = "Get user total trade volume value", + summary = "Get total trade volume value", + description = """GET /opex/v1/user/data/trade/volume/total. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- interval: Day, Week, Month, Year.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "interval", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string", description = "Interval: Day|Week|Month|Year")) - ], - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(type = "number", format = "double")) ]) ] + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "number"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] ) suspend fun getTotalTradeVolumeValue( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestParam interval: Interval + @Parameter( + name = "interval", + description = "Interval. For user data endpoints allowed values are Day, Week, Month, Year.", + required = true + ) + @RequestParam interval: LimitedInterval ): BigDecimal { - checkValidInterval(interval) + val interval = Interval.valueOf(interval.name) val uuid = securityContext.authentication.name return accountantProxy.getTotalTradeVolumeValue(uuid, interval) } @GetMapping("/fee") @Operation( - summary = "Get user fee settings", + summary = "Get user fee", + description = """GET /opex/v1/user/data/fee. +Security: Bearer user-token required. Requires authenticated user JWT. +""", security = [SecurityRequirement(name = "bearerAuth")], - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(implementation = UserFee::class)) ]) ] + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = UserFee::class))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] ) - suspend fun getUserFee(@CurrentSecurityContext securityContext: SecurityContext): UserFee { + suspend fun getUserFee( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ): UserFee { return accountantProxy.getUserFee(securityContext.authentication.name) } @GetMapping("/withdraw/volume/total") @Operation( - summary = "Get user total withdraw volume value", + summary = "Get total withdraw volume value", + description = """GET /opex/v1/user/data/withdraw/volume/total. +Behavior: `interval` is optional. Accepted labels map to Day, Week, Month, Year where supported. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- interval: Day, Week, Month, Year.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "interval", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string", description = "Optional label; maps to Interval by label")) - ], - responses = [ ApiResponse(responseCode = "200", description = "OK", content = [ Content(mediaType = "application/json", schema = Schema(type = "number", format = "double")) ]) ] + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] ) suspend fun getTotalWithdrawVolumeValue( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestParam(required = false) interval: String? + @Parameter( + name = "interval", + description = "Interval. For user data endpoints allowed values are Day, Week, Month, Year. ", + required = false + ) + @RequestParam(required = false) interval: LimitedInterval? ): BigDecimal = accountantProxy.getTotalWithdrawVolumeValue( securityContext.authentication.name, - interval?.let(Interval::findByLabel) + interval?.let { Interval.valueOf(interval.name) } ) - - private fun checkValidInterval(interval: Interval) { - if (interval == Interval.Day || interval == Interval.Week || interval == Interval.Month || interval == Interval.Year) - return - throw OpexError.BadRequest.exception() - } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/co/nilin/opex/common/utils/LimitedInterval.kt b/common/src/main/kotlin/co/nilin/opex/common/utils/LimitedInterval.kt new file mode 100644 index 000000000..87a7bb7d6 --- /dev/null +++ b/common/src/main/kotlin/co/nilin/opex/common/utils/LimitedInterval.kt @@ -0,0 +1,32 @@ +package co.nilin.opex.common.utils + +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.* +import java.util.concurrent.TimeUnit + +enum class LimitedInterval(val label: String, val unit: TimeUnit, val duration: Long) { + + Day("1d", TimeUnit.DAYS, 1), + Week("1w", TimeUnit.DAYS, 7), + Month("1M", TimeUnit.DAYS, 31), + Year("1Y", TimeUnit.DAYS, 365); + + private fun getOffsetTime() = unit.toMillis(duration) + + fun getDate() = Date(Date().time - getOffsetTime()) + + fun getTime() = Date().time - getOffsetTime() + + fun getLocalDateTime(): LocalDateTime = with(Instant.ofEpochMilli(getDate().time)) { + LocalDateTime.ofInstant(this, ZoneId.systemDefault()) + } + + companion object { + fun findByLabel(label: String): LimitedInterval? { + return values().find { it.label == label } + } + } + +} \ No newline at end of file From f65bc8f866b2d4e3a16806ca5dbeff755681637d Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 25 May 2026 21:16:45 +0330 Subject: [PATCH 38/56] Update swagger data about user history services --- .../core/inout/UserSwapTransactionRequest.kt | 1 - .../opex/api/core/inout/WithdrawResponse.kt | 2 +- .../co/nilin/opex/api/core/spi/WalletProxy.kt | 4 +- .../opex/controller/UserHistoryController.kt | 648 +++++++++++++++++- .../api/ports/proxy/impl/WalletProxyImpl.kt | 4 +- .../opex/wallet/core/inout/WithdrawType.kt | 2 +- 6 files changed, 626 insertions(+), 35 deletions(-) diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt index b8b8f368e..02504e5e0 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/UserSwapTransactionRequest.kt @@ -2,7 +2,6 @@ package co.nilin.opex.api.core.inout data class UserSwapTransactionRequest( val userId: String? = null, - val currency: String?, val sourceSymbol: String?, val destSymbol: String?, val startTime: Long? = null, diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/WithdrawResponse.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/WithdrawResponse.kt index ced56abf9..9e9634efa 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/WithdrawResponse.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/inout/WithdrawResponse.kt @@ -26,5 +26,5 @@ class WithdrawResponse( val otpRequired: Int? = 0, ) enum class WithdrawType { - CARD_TO_CARD, SHEBA, ON_CHAIN, OFF_CHAIN + ON_CHAIN, OFF_CHAIN } \ No newline at end of file diff --git a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt index 41a3dd1b5..a16754629 100644 --- a/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt +++ b/api/api-core/src/main/kotlin/co/nilin/opex/api/core/spi/WalletProxy.kt @@ -124,8 +124,8 @@ interface WalletProxy { suspend fun getQuoteCurrencies(): List - suspend fun getSwapTransactions(token: String, request: UserTransactionRequest): List - suspend fun getSwapTransactionsCount(token: String, request: UserTransactionRequest): Long + suspend fun getSwapTransactions(token: String, request: UserSwapTransactionRequest): List + suspend fun getSwapTransactionsCount(token: String, request: UserSwapTransactionRequest): Long suspend fun requestWithdrawOTP(token: String, withdrawUuid: String, otpType: OTPType): TempOtpResponse suspend fun verifyWithdrawOTP( diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt index cb90e5c3c..c65236dfc 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt @@ -7,27 +7,90 @@ import co.nilin.opex.api.ports.opex.data.OrderDataResponse import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.toResponse import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/user") +@Tag( + name = "User History", + description = "Authenticated user order, trade, deposit, withdraw, transaction, and swap history operations." +) class UserHistoryController( private val marketUserDataProxy: MarketUserDataProxy, - private val walletProxy: WalletProxy, + private val walletProxy: WalletProxy ) { @GetMapping("/history/order") + @Operation( + summary = "Get order history", + description = """GET /opex/v1/user/history/order. +Behavior: Optional filters include symbol, time range, orderType, direction, limit, and offset. `orderType`: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. `direction`: BUY, SELL. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = OrderDataResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getOrderHistory( + @Parameter( + name = "symbol", + description = "Trading pair or currency symbol, depending on endpoint.", + required = false + ) @RequestParam symbol: String?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter( + name = "orderType", + description = "Order type. Allowed values: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER.", + required = false + ) @RequestParam orderType: MatchingOrderType?, + @Parameter( + name = "direction", + description = "Order/trade direction. Allowed values: BUY, SELL.", + required = false + ) @RequestParam direction: OrderDirection?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, + @Parameter(name = "offset", description = "Optional page offset.", required = false) @RequestParam offset: Int?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return marketUserDataProxy.getOrderHistory( securityContext.authentication.name, @@ -37,18 +100,64 @@ class UserHistoryController( orderType, direction, limit ?: 10, - offset ?: 0, + offset ?: 0 ).map { it.toResponse() } } @GetMapping("/history/order/count") + @Operation( + summary = "Get order history count", + description = """GET /opex/v1/user/history/order/count. +Behavior: Same filters as order history, but returns count only. `orderType`: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. `direction`: BUY, SELL. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getOrderHistoryCount( + @Parameter( + name = "symbol", + description = "Trading pair or currency symbol, depending on endpoint.", + required = false + ) @RequestParam symbol: String?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter( + name = "orderType", + description = "Order type. Allowed values: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER.", + required = false + ) @RequestParam orderType: MatchingOrderType?, + @Parameter( + name = "direction", + description = "Order/trade direction. Allowed values: BUY, SELL.", + required = false + ) @RequestParam direction: OrderDirection?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): Long { return marketUserDataProxy.getOrderHistoryCount( securityContext.authentication.name, @@ -56,19 +165,65 @@ class UserHistoryController( startTime, endTime, orderType, - direction, + direction ) } @GetMapping("/history/trade") + @Operation( + summary = "Get trade history", + description = """GET /opex/v1/user/history/trade. +Behavior: Optional filters include symbol, time range, direction, limit, and offset. `direction`: BUY, SELL. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = Trade::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getTradeHistory( + @Parameter( + name = "symbol", + description = "Trading pair or currency symbol, depending on endpoint.", + required = false + ) @RequestParam symbol: String?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter( + name = "direction", + description = "Order/trade direction. Allowed values: BUY, SELL.", + required = false + ) @RequestParam direction: OrderDirection?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, + @Parameter(name = "offset", description = "Optional page offset.", required = false) @RequestParam offset: Int?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return marketUserDataProxy.getTradeHistory( securityContext.authentication.name, symbol, startTime, endTime, direction, limit ?: 10, offset ?: 0 @@ -76,12 +231,53 @@ class UserHistoryController( } @GetMapping("/history/trade/count") + @Operation( + summary = "Get trade history count", + description = """GET /opex/v1/user/history/trade/count. +Behavior: Same filters as trade history, but returns count only. `direction`: BUY, SELL. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getTradeHistoryCount( + @Parameter( + name = "symbol", + description = "Trading pair or currency symbol, depending on endpoint.", + required = false + ) @RequestParam symbol: String?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter( + name = "direction", + description = "Order/trade direction. Allowed values: BUY, SELL.", + required = false + ) @RequestParam direction: OrderDirection?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): Long { return marketUserDataProxy.getTradeHistoryCount( securityContext.authentication.name, symbol, startTime, endTime, direction @@ -89,15 +285,62 @@ class UserHistoryController( } @GetMapping("/history/withdraw") + @Operation( + summary = "Get withdraw history", + description = """GET /opex/v1/user/history/withdraw. +Behavior: Optional filters include currency, status, time range, pagination, and sorting. `status`: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = WithdrawResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getWithdrawHistory( + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) @RequestParam currency: String?, + @Parameter( + name = "status", + description = "Withdraw status. Allowed values: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.", + required = false + ) @RequestParam status: WithdrawStatus?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, + @Parameter(name = "offset", description = "Optional page offset.", required = false) @RequestParam offset: Int?, + @Parameter( + name = "ascendingByTime", + description = "Optional sorting flag. true sorts ascending by time; false sorts descending where supported.", + required = false + ) @RequestParam ascendingByTime: Boolean?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return walletProxy.getWithdrawTransactions( securityContext.jwtAuthentication().name, @@ -108,17 +351,54 @@ class UserHistoryController( endTime, limit ?: 10, offset ?: 0, - ascendingByTime, + ascendingByTime ) } @GetMapping("/history/withdraw/count") + @Operation( + summary = "Get withdraw history count", + description = """GET /opex/v1/user/history/withdraw/count. +Behavior: Same filters as withdraw history, but returns count only. `status`: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getWithdrawHistoryCount( + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) @RequestParam currency: String?, + @Parameter( + name = "status", + description = "Withdraw status. Allowed values: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.", + required = false + ) @RequestParam status: WithdrawStatus?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): Long { return walletProxy.getWithdrawTransactionsCount( securityContext.jwtAuthentication().name, @@ -126,19 +406,61 @@ class UserHistoryController( currency, status, startTime, - endTime, + endTime ) } @GetMapping("/history/deposit") + @Operation( + summary = "Get deposit history", + description = """GET /opex/v1/user/history/deposit. +Behavior: Optional filters include currency, time range, pagination, and sorting. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = DepositHistoryResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getDepositHistory( + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) @RequestParam currency: String?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, + @Parameter(name = "offset", description = "Optional page offset.", required = false) @RequestParam offset: Int?, + @Parameter( + name = "ascendingByTime", + description = "Optional sorting flag. true sorts ascending by time; false sorts descending where supported.", + required = false + ) @RequestParam ascendingByTime: Boolean?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return walletProxy.getDepositTransactions( securityContext.jwtAuthentication().name, @@ -148,36 +470,114 @@ class UserHistoryController( endTime, limit ?: 10, offset ?: 0, - ascendingByTime, + ascendingByTime ) } @GetMapping("/history/deposit/count") + @Operation( + summary = "Get deposit history count", + description = """GET /opex/v1/user/history/deposit/count. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getDepositHistoryCount( + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) @RequestParam currency: String?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): Long { return walletProxy.getDepositTransactionsCount( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), currency, startTime, - endTime, + endTime ) } @GetMapping("/history/transaction") + @Operation( + summary = "Get transaction history", + description = """GET /opex/v1/user/history/transaction. +Behavior: Optional filters include currency, category, time range, pagination, and sorting. `category`: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = UserTransactionHistory::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getTransactionHistory( + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) @RequestParam currency: String?, + @Parameter( + name = "category", + description = "Transaction category. Allowed values: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.", + required = false + ) @RequestParam category: UserTransactionCategory?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, + @Parameter(name = "offset", description = "Optional page offset.", required = false) @RequestParam offset: Int?, + @Parameter( + name = "ascendingByTime", + description = "Optional sorting flag. true sorts ascending by time; false sorts descending where supported.", + required = false + ) @RequestParam ascendingByTime: Boolean?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return walletProxy.getTransactions( securityContext.jwtAuthentication().name, @@ -188,17 +588,54 @@ class UserHistoryController( endTime, limit ?: 10, offset ?: 0, - ascendingByTime, + ascendingByTime ) } @GetMapping("/history/transaction/count") + @Operation( + summary = "Get transaction history count", + description = """GET /opex/v1/user/history/transaction/count. +Behavior: Same filters as transaction history, but returns count only. `category`: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getTransactionHistoryCount( + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) @RequestParam currency: String?, + @Parameter( + name = "category", + description = "Transaction category. Allowed values: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.", + required = false + ) @RequestParam category: UserTransactionCategory?, + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): Long { return walletProxy.getTransactionsCount( securityContext.jwtAuthentication().name, @@ -206,71 +643,226 @@ class UserHistoryController( currency, category, startTime, - endTime, + endTime ) } @GetMapping("/summary/trade") + @Operation( + summary = "Get trade transaction summary", + description = """GET /opex/v1/user/summary/trade. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getTradeTransactionSummary( + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return walletProxy.getUserTradeTransactionSummary( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), startTime, endTime, - limit, + limit ) } @GetMapping("/summary/deposit") + @Operation( + summary = "Get deposit summary", + description = """GET /opex/v1/user/summary/deposit. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getDepositSummary( + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return walletProxy.getUserDepositSummary( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), startTime, endTime, - limit, + limit ) } @GetMapping("/summary/withdraw") + @Operation( + summary = "Get withdraw summary", + description = """GET /opex/v1/user/summary/withdraw. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getWithdrawSummary( + @Parameter( + name = "startTime", + description = "Optional start timestamp in epoch milliseconds.", + required = false + ) @RequestParam startTime: Long?, + @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) @RequestParam endTime: Long?, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, - @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext ): List { return walletProxy.getUserWithdrawSummary( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), startTime, endTime, - limit, + limit ) } @PostMapping("/history/swap") + @Operation( + summary = "Get swap history", + description = """POST /opex/v1/user/history/swap. +Behavior: Request body contains swap history filters. Pagination and time range are handled by the request schema. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = SwapResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getSwapHistory( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UserTransactionRequest + @RequestBody request: UserSwapTransactionRequest ): List { return walletProxy.getSwapTransactions(securityContext.jwtAuthentication().tokenValue(), request) } @PostMapping("/history/swap/count") + @Operation( + summary = "Get swap history count", + description = """POST /opex/v1/user/history/swap/count. +Behavior: Same filter body as swap history, but returns count only. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. +- direction: BUY, SELL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getSwapHistoryCount( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UserTransactionRequest + @RequestBody request: UserSwapTransactionRequest ): Long { return walletProxy.getSwapTransactionsCount(securityContext.jwtAuthentication().tokenValue(), request) } -} \ No newline at end of file +} diff --git a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt index c37c30936..a16a07d5e 100644 --- a/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt +++ b/api/api-ports/api-proxy-rest/src/main/kotlin/co/nilin/opex/api/ports/proxy/impl/WalletProxyImpl.kt @@ -421,7 +421,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC } } - override suspend fun getSwapTransactions(token: String, request: UserTransactionRequest): List { + override suspend fun getSwapTransactions(token: String, request: UserSwapTransactionRequest): List { return webClient.post() .uri("$baseUrl/v1/swap/history") .accept(MediaType.APPLICATION_JSON) @@ -436,7 +436,7 @@ class WalletProxyImpl(@Qualifier("generalWebClient") private val webClient: WebC override suspend fun getSwapTransactionsCount( token: String, - request: UserTransactionRequest + request: UserSwapTransactionRequest ): Long { return webClient.post() .uri("$baseUrl/v1/swap/history/count") diff --git a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawType.kt b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawType.kt index 98ae7851c..2f93455f3 100644 --- a/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawType.kt +++ b/wallet/wallet-core/src/main/kotlin/co/nilin/opex/wallet/core/inout/WithdrawType.kt @@ -1,5 +1,5 @@ package co.nilin.opex.wallet.core.inout enum class WithdrawType { - CARD_TO_CARD, SHEBA, ON_CHAIN + OFF_CHAIN, ON_CHAIN } \ No newline at end of file From 2900e55d5cbc0953b72ced8c1a51097250a00fd8 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Mon, 25 May 2026 21:36:06 +0330 Subject: [PATCH 39/56] Update swagger data about user history services --- .../opex/controller/UserHistoryController.kt | 578 ++++++++++-------- 1 file changed, 314 insertions(+), 264 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt index c65236dfc..9b59872c5 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserHistoryController.kt @@ -23,33 +23,38 @@ import org.springframework.web.bind.annotation.* @RequestMapping("/opex/v1/user") @Tag( name = "User History", - description = "Authenticated user order, trade, deposit, withdraw, transaction, and swap history operations." + description = """Authenticated user history, summaries, and swap-history operations.""" ) class UserHistoryController( private val marketUserDataProxy: MarketUserDataProxy, - private val walletProxy: WalletProxy + private val walletProxy: WalletProxy, ) { @GetMapping("/history/order") @Operation( summary = "Get order history", description = """GET /opex/v1/user/history/order. -Behavior: Optional filters include symbol, time range, orderType, direction, limit, and offset. `orderType`: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. `direction`: BUY, SELL. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` defaults to 10 and `offset` defaults to 0 when omitted. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- orderType: LIMIT_ORDER, MARKET_ORDER. +- direction: ASK, BID.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = OrderDataResponse::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = OrderDataResponse::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -59,38 +64,34 @@ Allowed values: ] ) suspend fun getOrderHistory( - @Parameter( - name = "symbol", - description = "Trading pair or currency symbol, depending on endpoint.", - required = false - ) - @RequestParam symbol: String?, + @Parameter(name = "symbol", description = "Optional trading pair symbol.", required = false) + @RequestParam(name = "symbol", required = false) symbol: String?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, + @RequestParam(name = "endTime", required = false) endTime: Long?, @Parameter( name = "orderType", - description = "Order type. Allowed values: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER.", + description = "Optional order type filter. Allowed values: LIMIT_ORDER, MARKET_ORDER.", required = false ) - @RequestParam orderType: MatchingOrderType?, + @RequestParam(name = "orderType", required = false) orderType: MatchingOrderType?, @Parameter( name = "direction", - description = "Order/trade direction. Allowed values: BUY, SELL.", + description = "Optional order direction filter. Allowed values: ASK, BID.", required = false ) - @RequestParam direction: OrderDirection?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, - @Parameter(name = "offset", description = "Optional page offset.", required = false) - @RequestParam offset: Int?, + @RequestParam(name = "direction", required = false) direction: OrderDirection?, + @Parameter(name = "limit", description = "Optional page size. Defaults to 10 when omitted.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, + @Parameter(name = "offset", description = "Optional page offset. Defaults to 0 when omitted.", required = false) + @RequestParam(name = "offset", required = false) offset: Int?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return marketUserDataProxy.getOrderHistory( securityContext.authentication.name, @@ -100,27 +101,29 @@ Allowed values: orderType, direction, limit ?: 10, - offset ?: 0 + offset ?: 0, ).map { it.toResponse() } } @GetMapping("/history/order/count") @Operation( - summary = "Get order history count", + summary = "Count order history", description = """GET /opex/v1/user/history/order/count. -Behavior: Same filters as order history, but returns count only. `orderType`: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. `direction`: BUY, SELL. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- orderType: LIMIT_ORDER, MARKET_ORDER. +- direction: ASK, BID.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + content = [Content(mediaType = "application/json", schema = Schema(implementation = Long::class))] ), ApiResponse( responseCode = "401", @@ -130,34 +133,30 @@ Allowed values: ] ) suspend fun getOrderHistoryCount( - @Parameter( - name = "symbol", - description = "Trading pair or currency symbol, depending on endpoint.", - required = false - ) - @RequestParam symbol: String?, + @Parameter(name = "symbol", description = "Optional trading pair symbol.", required = false) + @RequestParam(name = "symbol", required = false) symbol: String?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, + @RequestParam(name = "endTime", required = false) endTime: Long?, @Parameter( name = "orderType", - description = "Order type. Allowed values: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER.", + description = "Optional order type filter. Allowed values: LIMIT_ORDER, MARKET_ORDER.", required = false ) - @RequestParam orderType: MatchingOrderType?, + @RequestParam(name = "orderType", required = false) orderType: MatchingOrderType?, @Parameter( name = "direction", - description = "Order/trade direction. Allowed values: BUY, SELL.", + description = "Optional order direction filter. Allowed values: ASK, BID.", required = false ) - @RequestParam direction: OrderDirection?, + @RequestParam(name = "direction", required = false) direction: OrderDirection?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): Long { return marketUserDataProxy.getOrderHistoryCount( securityContext.authentication.name, @@ -165,7 +164,7 @@ Allowed values: startTime, endTime, orderType, - direction + direction, ) } @@ -173,22 +172,26 @@ Allowed values: @Operation( summary = "Get trade history", description = """GET /opex/v1/user/history/trade. -Behavior: Optional filters include symbol, time range, direction, limit, and offset. `direction`: BUY, SELL. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` defaults to 10 and `offset` defaults to 0 when omitted. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- direction: ASK, BID.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = Trade::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = Trade::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -198,55 +201,58 @@ Allowed values: ] ) suspend fun getTradeHistory( - @Parameter( - name = "symbol", - description = "Trading pair or currency symbol, depending on endpoint.", - required = false - ) - @RequestParam symbol: String?, + @Parameter(name = "symbol", description = "Optional trading pair symbol.", required = false) + @RequestParam(name = "symbol", required = false) symbol: String?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, + @RequestParam(name = "endTime", required = false) endTime: Long?, @Parameter( name = "direction", - description = "Order/trade direction. Allowed values: BUY, SELL.", + description = "Optional trade direction filter. Allowed values: ASK, BID.", required = false ) - @RequestParam direction: OrderDirection?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, - @Parameter(name = "offset", description = "Optional page offset.", required = false) - @RequestParam offset: Int?, + @RequestParam(name = "direction", required = false) direction: OrderDirection?, + @Parameter(name = "limit", description = "Optional page size. Defaults to 10 when omitted.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, + @Parameter(name = "offset", description = "Optional page offset. Defaults to 0 when omitted.", required = false) + @RequestParam(name = "offset", required = false) offset: Int?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return marketUserDataProxy.getTradeHistory( - securityContext.authentication.name, symbol, startTime, endTime, direction, limit ?: 10, offset ?: 0 + securityContext.authentication.name, + symbol, + startTime, + endTime, + direction, + limit ?: 10, + offset ?: 0 ) } @GetMapping("/history/trade/count") @Operation( - summary = "Get trade history count", + summary = "Count trade history", description = """GET /opex/v1/user/history/trade/count. -Behavior: Same filters as trade history, but returns count only. `direction`: BUY, SELL. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- direction: ASK, BID.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + content = [Content(mediaType = "application/json", schema = Schema(implementation = Long::class))] ), ApiResponse( responseCode = "401", @@ -256,31 +262,31 @@ Allowed values: ] ) suspend fun getTradeHistoryCount( - @Parameter( - name = "symbol", - description = "Trading pair or currency symbol, depending on endpoint.", - required = false - ) - @RequestParam symbol: String?, + @Parameter(name = "symbol", description = "Optional trading pair symbol.", required = false) + @RequestParam(name = "symbol", required = false) symbol: String?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, + @RequestParam(name = "endTime", required = false) endTime: Long?, @Parameter( name = "direction", - description = "Order/trade direction. Allowed values: BUY, SELL.", + description = "Optional trade direction filter. Allowed values: ASK, BID.", required = false ) - @RequestParam direction: OrderDirection?, + @RequestParam(name = "direction", required = false) direction: OrderDirection?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): Long { return marketUserDataProxy.getTradeHistoryCount( - securityContext.authentication.name, symbol, startTime, endTime, direction + securityContext.authentication.name, + symbol, + startTime, + endTime, + direction ) } @@ -288,22 +294,28 @@ Allowed values: @Operation( summary = "Get withdraw history", description = """GET /opex/v1/user/history/withdraw. -Behavior: Optional filters include currency, status, time range, pagination, and sorting. `status`: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` defaults to 10 and `offset` defaults to 0 when omitted. +- `ascendingByTime` controls time sorting when supported. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- transferMethod in response: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = WithdrawResponse::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = WithdrawResponse::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -313,34 +325,34 @@ Allowed values: ] ) suspend fun getWithdrawHistory( - @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) - @RequestParam currency: String?, + @Parameter(name = "currency", description = "Optional currency symbol.", required = false) + @RequestParam(name = "currency", required = false) currency: String?, @Parameter( name = "status", - description = "Withdraw status. Allowed values: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.", + description = "Optional withdraw status. Allowed values: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.", required = false ) - @RequestParam status: WithdrawStatus?, + @RequestParam(name = "status", required = false) status: WithdrawStatus?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, - @Parameter(name = "offset", description = "Optional page offset.", required = false) - @RequestParam offset: Int?, + @RequestParam(name = "endTime", required = false) endTime: Long?, + @Parameter(name = "limit", description = "Optional page size. Defaults to 10 when omitted.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, + @Parameter(name = "offset", description = "Optional page offset. Defaults to 0 when omitted.", required = false) + @RequestParam(name = "offset", required = false) offset: Int?, @Parameter( name = "ascendingByTime", description = "Optional sorting flag. true sorts ascending by time; false sorts descending where supported.", required = false ) - @RequestParam ascendingByTime: Boolean?, + @RequestParam(name = "ascendingByTime", required = false) ascendingByTime: Boolean?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return walletProxy.getWithdrawTransactions( securityContext.jwtAuthentication().name, @@ -351,27 +363,28 @@ Allowed values: endTime, limit ?: 10, offset ?: 0, - ascendingByTime + ascendingByTime, ) } @GetMapping("/history/withdraw/count") @Operation( - summary = "Get withdraw history count", + summary = "Count withdraw history", description = """GET /opex/v1/user/history/withdraw/count. -Behavior: Same filters as withdraw history, but returns count only. `status`: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + content = [Content(mediaType = "application/json", schema = Schema(implementation = Long::class))] ), ApiResponse( responseCode = "401", @@ -381,24 +394,24 @@ Allowed values: ] ) suspend fun getWithdrawHistoryCount( - @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) - @RequestParam currency: String?, + @Parameter(name = "currency", description = "Optional currency symbol.", required = false) + @RequestParam(name = "currency", required = false) currency: String?, @Parameter( name = "status", - description = "Withdraw status. Allowed values: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.", + description = "Optional withdraw status. Allowed values: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.", required = false ) - @RequestParam status: WithdrawStatus?, + @RequestParam(name = "status", required = false) status: WithdrawStatus?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, + @RequestParam(name = "endTime", required = false) endTime: Long?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): Long { return walletProxy.getWithdrawTransactionsCount( securityContext.jwtAuthentication().name, @@ -406,7 +419,7 @@ Allowed values: currency, status, startTime, - endTime + endTime, ) } @@ -414,22 +427,29 @@ Allowed values: @Operation( summary = "Get deposit history", description = """GET /opex/v1/user/history/deposit. -Behavior: Optional filters include currency, time range, pagination, and sorting. Security: Bearer user-token required. Requires authenticated user JWT. -Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` defaults to 10 and `offset` defaults to 0 when omitted. +- `ascendingByTime` controls time sorting when supported. + +Allowed values in response: +- status: PROCESSING, DONE, INVALID. +- type: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = DepositHistoryResponse::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = DepositHistoryResponse::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -439,28 +459,28 @@ Allowed values: ] ) suspend fun getDepositHistory( - @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) - @RequestParam currency: String?, + @Parameter(name = "currency", description = "Optional currency symbol.", required = false) + @RequestParam(name = "currency", required = false) currency: String?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, - @Parameter(name = "offset", description = "Optional page offset.", required = false) - @RequestParam offset: Int?, + @RequestParam(name = "endTime", required = false) endTime: Long?, + @Parameter(name = "limit", description = "Optional page size. Defaults to 10 when omitted.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, + @Parameter(name = "offset", description = "Optional page offset. Defaults to 0 when omitted.", required = false) + @RequestParam(name = "offset", required = false) offset: Int?, @Parameter( name = "ascendingByTime", description = "Optional sorting flag. true sorts ascending by time; false sorts descending where supported.", required = false ) - @RequestParam ascendingByTime: Boolean?, + @RequestParam(name = "ascendingByTime", required = false) ascendingByTime: Boolean?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return walletProxy.getDepositTransactions( securityContext.jwtAuthentication().name, @@ -470,26 +490,25 @@ Allowed values: endTime, limit ?: 10, offset ?: 0, - ascendingByTime + ascendingByTime, ) } @GetMapping("/history/deposit/count") @Operation( - summary = "Get deposit history count", + summary = "Count deposit history", description = """GET /opex/v1/user/history/deposit/count. Security: Bearer user-token required. Requires authenticated user JWT. -Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + content = [Content(mediaType = "application/json", schema = Schema(implementation = Long::class))] ), ApiResponse( responseCode = "401", @@ -499,25 +518,25 @@ Allowed values: ] ) suspend fun getDepositHistoryCount( - @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) - @RequestParam currency: String?, + @Parameter(name = "currency", description = "Optional currency symbol.", required = false) + @RequestParam(name = "currency", required = false) currency: String?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, + @RequestParam(name = "endTime", required = false) endTime: Long?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): Long { return walletProxy.getDepositTransactionsCount( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), currency, startTime, - endTime + endTime, ) } @@ -525,22 +544,27 @@ Allowed values: @Operation( summary = "Get transaction history", description = """GET /opex/v1/user/history/transaction. -Behavior: Optional filters include currency, category, time range, pagination, and sorting. `category`: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` defaults to 10 and `offset` defaults to 0 when omitted. +- `ascendingByTime` controls time sorting when supported. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = UserTransactionHistory::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = UserTransactionHistory::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -550,34 +574,34 @@ Allowed values: ] ) suspend fun getTransactionHistory( - @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) - @RequestParam currency: String?, + @Parameter(name = "currency", description = "Optional currency symbol.", required = false) + @RequestParam(name = "currency", required = false) currency: String?, @Parameter( name = "category", - description = "Transaction category. Allowed values: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.", + description = "Optional transaction category. Allowed values: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.", required = false ) - @RequestParam category: UserTransactionCategory?, + @RequestParam(name = "category", required = false) category: UserTransactionCategory?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, - @Parameter(name = "offset", description = "Optional page offset.", required = false) - @RequestParam offset: Int?, + @RequestParam(name = "endTime", required = false) endTime: Long?, + @Parameter(name = "limit", description = "Optional page size. Defaults to 10 when omitted.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, + @Parameter(name = "offset", description = "Optional page offset. Defaults to 0 when omitted.", required = false) + @RequestParam(name = "offset", required = false) offset: Int?, @Parameter( name = "ascendingByTime", description = "Optional sorting flag. true sorts ascending by time; false sorts descending where supported.", required = false ) - @RequestParam ascendingByTime: Boolean?, + @RequestParam(name = "ascendingByTime", required = false) ascendingByTime: Boolean?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return walletProxy.getTransactions( securityContext.jwtAuthentication().name, @@ -588,27 +612,28 @@ Allowed values: endTime, limit ?: 10, offset ?: 0, - ascendingByTime + ascendingByTime, ) } @GetMapping("/history/transaction/count") @Operation( - summary = "Get transaction history count", + summary = "Count transaction history", description = """GET /opex/v1/user/history/transaction/count. -Behavior: Same filters as transaction history, but returns count only. `category`: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + content = [Content(mediaType = "application/json", schema = Schema(implementation = Long::class))] ), ApiResponse( responseCode = "401", @@ -618,24 +643,24 @@ Allowed values: ] ) suspend fun getTransactionHistoryCount( - @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) - @RequestParam currency: String?, + @Parameter(name = "currency", description = "Optional currency symbol.", required = false) + @RequestParam(name = "currency", required = false) currency: String?, @Parameter( name = "category", - description = "Transaction category. Allowed values: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.", + description = "Optional transaction category. Allowed values: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.", required = false ) - @RequestParam category: UserTransactionCategory?, + @RequestParam(name = "category", required = false) category: UserTransactionCategory?, @Parameter( name = "startTime", description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, + @RequestParam(name = "endTime", required = false) endTime: Long?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): Long { return walletProxy.getTransactionsCount( securityContext.jwtAuthentication().name, @@ -643,29 +668,31 @@ Allowed values: currency, category, startTime, - endTime + endTime, ) } @GetMapping("/summary/trade") @Operation( - summary = "Get trade transaction summary", + summary = "Get trade summary", description = """GET /opex/v1/user/summary/trade. Security: Bearer user-token required. Requires authenticated user JWT. -Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` limits the number of summary rows when supported.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -680,20 +707,20 @@ Allowed values: description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, + @RequestParam(name = "endTime", required = false) endTime: Long?, + @Parameter(name = "limit", description = "Optional number of summary rows.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return walletProxy.getUserTradeTransactionSummary( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), startTime, endTime, - limit + limit, ) } @@ -702,20 +729,22 @@ Allowed values: summary = "Get deposit summary", description = """GET /opex/v1/user/summary/deposit. Security: Bearer user-token required. Requires authenticated user JWT. -Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` limits the number of summary rows when supported.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -730,20 +759,20 @@ Allowed values: description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, + @RequestParam(name = "endTime", required = false) endTime: Long?, + @Parameter(name = "limit", description = "Optional number of summary rows.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return walletProxy.getUserDepositSummary( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), startTime, endTime, - limit + limit, ) } @@ -752,20 +781,22 @@ Allowed values: summary = "Get withdraw summary", description = """GET /opex/v1/user/summary/withdraw. Security: Bearer user-token required. Requires authenticated user JWT. -Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` limits the number of summary rows when supported.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TransactionSummary::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -780,20 +811,20 @@ Allowed values: description = "Optional start timestamp in epoch milliseconds.", required = false ) - @RequestParam startTime: Long?, + @RequestParam(name = "startTime", required = false) startTime: Long?, @Parameter(name = "endTime", description = "Optional end timestamp in epoch milliseconds.", required = false) - @RequestParam endTime: Long?, - @Parameter(name = "limit", description = "Optional page size.", required = false) - @RequestParam limit: Int?, + @RequestParam(name = "endTime", required = false) endTime: Long?, + @Parameter(name = "limit", description = "Optional number of summary rows.", required = false) + @RequestParam(name = "limit", required = false) limit: Int?, @Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext + @CurrentSecurityContext securityContext: SecurityContext, ): List { return walletProxy.getUserWithdrawSummary( securityContext.jwtAuthentication().name, securityContext.jwtAuthentication().tokenValue(), startTime, endTime, - limit + limit, ) } @@ -801,22 +832,33 @@ Allowed values: @Operation( summary = "Get swap history", description = """POST /opex/v1/user/history/swap. -Behavior: Request body contains swap history filters. Pagination and time range are handled by the request schema. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. +- `limit` defaults to 10 and `offset` defaults to 0 when omitted. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- status: Created, Expired, Committed.""", security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = UserSwapTransactionRequest::class) + )] + ), responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = SwapResponse::class)) - )] + content = [ + Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = SwapResponse::class)) + ) + ] ), ApiResponse( responseCode = "401", @@ -835,21 +877,29 @@ Allowed values: @PostMapping("/history/swap/count") @Operation( - summary = "Get swap history count", + summary = "Count swap history", description = """POST /opex/v1/user/history/swap/count. -Behavior: Same filter body as swap history, but returns count only. Security: Bearer user-token required. Requires authenticated user JWT. + +Behavior / Validation: +- Optional filters are applied only when provided. +- `startTime` and `endTime` are epoch milliseconds. + Allowed values: -- orderType: LIMIT, MARKET, STOP_LOSS, STOP_LOSS_LIMIT, TAKE_PROFIT, TAKE_PROFIT_LIMIT, LIMIT_MAKER. -- direction: BUY, SELL. -- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. -- transaction category: TRADE, DEPOSIT, DEPOSIT_TO, WITHDRAW_FROM, WITHDRAW, FEE, SWAP, REFERRAL_COMMISSION, REFERRAL_KYC_REWARD, REFERENT_COMMISSION, KYC_ACCEPTED_REWARD, SYSTEM.""", +- status: Created, Expired, Committed.""", security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = UserSwapTransactionRequest::class) + )] + ), responses = [ ApiResponse( responseCode = "200", description = "Successful response.", - content = [Content(mediaType = "application/json", schema = Schema(type = "integer", format = "int64"))] + content = [Content(mediaType = "application/json", schema = Schema(implementation = Long::class))] ), ApiResponse( responseCode = "401", From e6d6c2c3aee130441ec835af95b08dd5c6c440bd Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Tue, 26 May 2026 11:19:03 +0330 Subject: [PATCH 40/56] Update swagger data about voucher services --- .../opex/controller/VoucherController.kt | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt index ddabb2fac..f0e6ec518 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt @@ -4,44 +4,45 @@ import co.nilin.opex.api.core.inout.SubmitVoucherResponse import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.common.security.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.PutMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/voucher") -@Tag(name = "Voucher", description = "Voucher submission operations") +@Tag(name = "Voucher", description = "Authenticated voucher submission operations.") class VoucherController(private val walletProxy: WalletProxy) { @PutMapping("/{code}") @Operation( - summary = "Submit voucher code", + summary = "Submit voucher", + description = """PUT /opex/v1/voucher/{code}. +Security: Bearer user-token required. Required authority: PERM_voucher:submit.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "code", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) - ], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = SubmitVoucherResponse::class)) - ]) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = SubmitVoucherResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: PERM_voucher:submit. No response body.", content = [Content()]) ] ) suspend fun submitVoucher( + @Parameter(name = "code", description = "Voucher code.", required = true) @PathVariable code: String, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): SubmitVoucherResponse { return walletProxy.submitVoucher(code, securityContext.jwtAuthentication().tokenValue()) } -} \ No newline at end of file +} From c55a3ec29a41a8fe011caa3d4a8e13d441124fb7 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:01:33 +0330 Subject: [PATCH 41/56] Update swagger data about voucher, wallet and withdraw services --- .../opex/controller/VoucherController.kt | 2 +- .../opex/controller/WalletAdminController.kt | 71 ++++--- .../ports/opex/controller/WalletController.kt | 61 +++++- .../controller/WithdrawAdminController.kt | 94 ++++++++- .../opex/controller/WithdrawController.kt | 180 ++++++++++++++---- 5 files changed, 330 insertions(+), 78 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt index f0e6ec518..7489938f3 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt @@ -22,7 +22,7 @@ import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/voucher") -@Tag(name = "Voucher", description = "Authenticated voucher submission operations.") +@Tag(name = "Voucher", description = "Authenticated voucher submission operations.\n\nSource of values:\n- code is a server-issued voucher code.") class VoucherController(private val walletProxy: WalletProxy) { @PutMapping("/{code}") diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt index 25f6179ca..93f434c3d 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt @@ -5,52 +5,55 @@ import co.nilin.opex.api.core.inout.WalletTotal import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestParam -import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/admin/wallet") -@Tag(name = "Wallet Admin", description = "Admin operations on wallets") +@Tag(name = "Wallet Admin", description = "Admin wallet overview and total balance operations.\n\nSource of values:\n- currency is a server-provided currency symbol.\nAllowed values:\n- excludeSystem: true, false.") class WalletAdminController( private val walletProxy: WalletProxy ) { @GetMapping("/users") @Operation( - summary = "Admin: List users wallets", + summary = "Get users wallets", + description = """GET /opex/v1/admin/wallet/users. +Behavior: Optional filters include uuid, currency, excludeSystem, limit, and offset. `excludeSystem` defaults to false. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- excludeSystem: true, false.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "uuid", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string")), - Parameter(name = "currency", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "string")), - Parameter(name = "excludeSystem", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "boolean", defaultValue = "false")), - Parameter(name = "limit", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "integer", defaultValue = "10")), - Parameter(name = "offset", `in` = ParameterIn.QUERY, required = false, schema = Schema(type = "integer", defaultValue = "0")) - ], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletDataResponse::class))) - ]) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletDataResponse::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) suspend fun getUsersWallets( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "uuid", description = "User/profile/terminal UUID depending on the endpoint context.", required = false) @RequestParam(required = false) uuid: String?, + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = false) @RequestParam(required = false) currency: String?, + @Parameter(name = "excludeSystem", description = "Whether system wallets should be excluded from the result.", required = false) @RequestParam(required = false, defaultValue = "false") excludeSystem: Boolean, + @Parameter(name = "limit", description = "Optional page size.", required = false) @RequestParam limit: Int?, + @Parameter(name = "offset", description = "Optional page offset.", required = false) @RequestParam offset: Int? ): List { return walletProxy.getUsersWallets( @@ -65,29 +68,39 @@ class WalletAdminController( @GetMapping("/system/total") @Operation( - summary = "Admin: System wallets total", + summary = "Get system wallets total", + description = """GET /opex/v1/admin/wallet/system/total. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- excludeSystem: true, false.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletTotal::class))) - ]) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletTotal::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) - suspend fun getSystemWalletsTotal(@CurrentSecurityContext securityContext: SecurityContext): List { + suspend fun getSystemWalletsTotal(@Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext): List { return walletProxy.getSystemWalletsTotal(securityContext.jwtAuthentication().tokenValue()) } @GetMapping("/users/total") @Operation( - summary = "Admin: Users wallets total", + summary = "Get users wallets total", + description = """GET /opex/v1/admin/wallet/users/total. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- excludeSystem: true, false.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletTotal::class))) - ]) + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = WalletTotal::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) ] ) - suspend fun getUsersWalletsTotal(@CurrentSecurityContext securityContext: SecurityContext): List? { + suspend fun getUsersWalletsTotal(@Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext): List? { return walletProxy.getUsersWalletsTotal(securityContext.jwtAuthentication().tokenValue()) } } diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt index effbdc39d..b2c546c4f 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt @@ -15,18 +15,42 @@ import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController("walletOpexController") @RequestMapping("/opex/v1/wallet") +@Tag(name = "Wallet", description = "Authenticated user wallet asset, limits, and deposit address operations.\n\nAllowed values:\n- walletType values in related wallet responses/requests: MAIN, EXCHANGE, CASHOUT.\nSource of values:\n- symbol, currency and gatewayUuid are server-provided values.") class WalletController( private val walletProxy: WalletProxy, - private val bcGatewayProxy: BlockchainGatewayProxy, + private val bcGatewayProxy: BlockchainGatewayProxy ) { @GetMapping("/asset") + @Operation( + summary = "Get user assets", + description = """GET /opex/v1/wallet/asset. +Behavior: If `symbol` is omitted, all user wallet assets are returned. If provided, only that currency asset is returned. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- walletType values in related wallet responses/requests: MAIN, EXCHANGE, CASHOUT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = AssetResponse::class)))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun getUserAssets( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @RequestParam(required = false) symbol: String?, + @Parameter(name = "symbol", description = "Trading pair or currency symbol, depending on endpoint.", required = false) + @RequestParam(required = false) symbol: String? ): List { val auth = securityContext.jwtAuthentication() val result = arrayListOf() @@ -44,17 +68,46 @@ class WalletController( } @GetMapping("/limits") - suspend fun getWalletOwnerLimits(@CurrentSecurityContext securityContext: SecurityContext): OwnerLimitsResponse { + @Operation( + summary = "Get wallet owner limits", + description = """GET /opex/v1/wallet/limits. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- walletType values in related wallet responses/requests: MAIN, EXCHANGE, CASHOUT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = OwnerLimitsResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) + suspend fun getWalletOwnerLimits(@Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext): OwnerLimitsResponse { return walletProxy.getOwnerLimits( securityContext.jwtAuthentication().name, - securityContext.jwtAuthentication().tokenValue(), + securityContext.jwtAuthentication().tokenValue() ) } @GetMapping("/deposit/address") + @Operation( + summary = "Assign address", + description = """GET /opex/v1/wallet/deposit/address. +Source of values: `gatewayUuid` should come from server-provided gateway data for the selected currency/network. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- walletType values in related wallet responses/requests: MAIN, EXCHANGE, CASHOUT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = AssignAddressResponse::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun assignAddress( + @Parameter(name = "currency", description = "Currency symbol, e.g. USDT.", required = true) @RequestParam currency: String, + @Parameter(name = "gatewayUuid", description = "Gateway UUID.", required = true) @RequestParam gatewayUuid: String, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): AssignAddressResponse { diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt index 8fb440bee..50f1de903 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt @@ -8,18 +8,47 @@ import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* import java.math.BigDecimal +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/withdraw") +@Tag(name = "Withdraw Admin", description = "Admin manual withdraw and withdraw workflow operations.\n\nAllowed values:\n- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.\n- withdrawType: CARD_TO_CARD, SHEBA, ON_CHAIN, OFF_CHAIN.\n- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.\n- sourceWalletType where used: MAIN, EXCHANGE, CASHOUT.") class WithdrawAdminController( - private val walletProxy: WalletProxy, + private val walletProxy: WalletProxy ) { @PostMapping("/manually/{amount}_{symbol}/{sourceUuid}") + @Operation( + summary = "Withdraw manually", + description = """POST /opex/v1/admin/withdraw/manually/{amount}_{symbol}/{sourceUuid}. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- sourceWalletType where used: MAIN, EXCHANGE, CASHOUT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun withdrawManually( + @Parameter(name = "symbol", description = "Trading pair or currency symbol, depending on endpoint.", required = true) @PathVariable("symbol") symbol: String, + @Parameter(name = "sourceUuid", description = "Source wallet owner UUID.", required = true) @PathVariable("sourceUuid") sourceUuid: String, + @Parameter(name = "amount", description = "Withdraw amount.", required = true) @PathVariable("amount") amount: BigDecimal, @RequestBody request: ManualTransferRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext ): TransferResult { return walletProxy.withdrawManually( @@ -32,28 +61,83 @@ class WithdrawAdminController( } @PostMapping("/{withdrawUuid}/accept") + @Operation( + summary = "Start the process of the withdraw", + description = """POST /opex/v1/admin/withdraw/{withdrawUuid}/accept. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- sourceWalletType where used: MAIN, EXCHANGE, CASHOUT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = WithdrawActionResult::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun acceptWithdraw( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, - @PathVariable withdrawUuid: String, + @Parameter(name = "withdrawUuid", description = "Withdraw UUID.", required = true) + @PathVariable withdrawUuid: String ): WithdrawActionResult { return walletProxy.acceptWithdraw(securityContext.jwtAuthentication().tokenValue(), withdrawUuid) } @PostMapping("/{withdrawUuid}/done") + @Operation( + summary = "Done withdraw", + description = """POST /opex/v1/admin/withdraw/{withdrawUuid}/done. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- sourceWalletType where used: MAIN, EXCHANGE, CASHOUT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = WithdrawActionResult::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun doneWithdraw( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "withdrawUuid", description = "Withdraw UUID.", required = true) @PathVariable withdrawUuid: String, - @RequestBody request: WithdrawDoneRequest, + @RequestBody request: WithdrawDoneRequest ): WithdrawActionResult { return walletProxy.doneWithdraw(securityContext.jwtAuthentication().tokenValue(), withdrawUuid, request) } @PostMapping("/{withdrawUuid}/reject") + @Operation( + summary = "Reject withdraw", + description = """POST /opex/v1/admin/withdraw/{withdrawUuid}/reject. +Validation: Request body contains the rejection reason/details required by schema. +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: CARD_TO_CARD, SHEBA, ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD. +- sourceWalletType where used: MAIN, EXCHANGE, CASHOUT.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = WithdrawActionResult::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun rejectWithdraw( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "withdrawUuid", description = "Withdraw UUID.", required = true) @PathVariable withdrawUuid: String, - @RequestBody request: WithdrawRejectRequest, + @RequestBody request: WithdrawRejectRequest ): WithdrawActionResult { return walletProxy.rejectWithdraw(securityContext.jwtAuthentication().tokenValue(), withdrawUuid, request) } -} \ No newline at end of file +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt index b06d07a93..42a94b3c4 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawController.kt @@ -6,7 +6,6 @@ import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.enums.ParameterIn import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse @@ -18,26 +17,47 @@ import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/withdraw") -@Tag(name = "Withdraw", description = "User withdrawal operations") +@Tag(name = "Withdraw", description = "Authenticated user withdraw and OTP operations.") class WithdrawController( - private val walletProxy: WalletProxy, + private val walletProxy: WalletProxy ) { @PostMapping @Operation( summary = "Request withdraw", + description = """POST /opex/v1/withdraw. +Security: Bearer user-token required. Required authority: PERM_withdraw:write. + +Behavior: The response may require an OTP next action before the withdraw can continue. +Allowed values: +- otpType: SMS, EMAIL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.""", security = [SecurityRequirement(name = "bearerAuth")], - requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( - required = true, - content = [Content(mediaType = "application/json", schema = Schema(implementation = RequestWithdrawBody::class))] - ), responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = WithdrawActionResult::class)) - ]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = WithdrawActionResult::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: PERM_withdraw:write. No response body.", + content = [Content()] + ) ] ) suspend fun requestWithdraw( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody request: RequestWithdrawBody ): WithdrawActionResult? { @@ -50,14 +70,32 @@ class WithdrawController( @PutMapping("/{withdrawUuid}/cancel") @Operation( summary = "Cancel withdraw", + description = """PUT /opex/v1/withdraw/{withdrawUuid}/cancel. +Security: Bearer user-token required. Required authority: PERM_withdraw:write. +Allowed values: +- otpType: SMS, EMAIL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) - ], - responses = [ ApiResponse(responseCode = "200", description = "Cancelled") ] + responses = [ + ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: PERM_withdraw:write. No response body.", + content = [Content()] + ) + ] ) suspend fun cancelWithdraw( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "withdrawUuid", description = "Withdraw UUID.", required = true) @PathVariable withdrawUuid: String ) { walletProxy.cancelWithdraw( @@ -69,18 +107,34 @@ class WithdrawController( @GetMapping("/{withdrawUuid}") @Operation( summary = "Find withdraw", + description = """GET /opex/v1/withdraw/{withdrawUuid}. +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- otpType: SMS, EMAIL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")) - ], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = WithdrawResponse::class)) - ]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = WithdrawResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) suspend fun findWithdraw( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "withdrawUuid", description = "Withdraw UUID.", required = true) @PathVariable withdrawUuid: String ): WithdrawResponse { return walletProxy.findWithdraw( @@ -91,21 +145,45 @@ class WithdrawController( @PostMapping("/{withdrawUuid}/otp/{otpType}/request") @Operation( - summary = "Request withdraw OTP", + summary = "Request otp", + description = """POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request. +Validation: `otpType` allowed values: SMS, EMAIL. +Security: Bearer user-token required. Required authority: PERM_withdraw:write. + +Validation: `otpType` must be a supported OTP delivery type such as EMAIL or SMS. +Allowed values: +- otpType: SMS, EMAIL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")), - Parameter(name = "otpType", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string", description = "OTPType")) - ], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = TempOtpResponse::class)) - ]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = TempOtpResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: PERM_withdraw:write. No response body.", + content = [Content()] + ) ] ) suspend fun requestOTP( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "withdrawUuid", description = "Withdraw UUID.", required = true) @PathVariable withdrawUuid: String, + @Parameter(name = "otpType", description = "OTP delivery type. Allowed values: SMS, EMAIL.", required = true) @PathVariable otpType: OTPType ): TempOtpResponse { return walletProxy.requestWithdrawOTP(securityContext.jwtAuthentication().tokenValue(), withdrawUuid, otpType) @@ -113,24 +191,48 @@ class WithdrawController( @PostMapping("/{withdrawUuid}/otp/{otpType}/verify") @Operation( - summary = "Verify withdraw OTP", + summary = "Verify otp", + description = """POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify. +Validation: `otpType` allowed values: SMS, EMAIL. `otpCode` is required. +Security: Bearer user-token required. Required authority: PERM_withdraw:write. + +Validation: `otpType` must be a supported OTP delivery type such as EMAIL or SMS. `otpCode` is required for verification. +Allowed values: +- otpType: SMS, EMAIL. +- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE. +- withdrawType: ON_CHAIN, OFF_CHAIN. +- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.""", security = [SecurityRequirement(name = "bearerAuth")], - parameters = [ - Parameter(name = "withdrawUuid", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string")), - Parameter(name = "otpType", `in` = ParameterIn.PATH, required = true, schema = Schema(type = "string", description = "OTPType")), - Parameter(name = "otpCode", `in` = ParameterIn.QUERY, required = true, schema = Schema(type = "string")) - ], responses = [ - ApiResponse(responseCode = "200", description = "OK", content = [ - Content(mediaType = "application/json", schema = Schema(implementation = WithdrawActionResult::class)) - ]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = WithdrawActionResult::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: PERM_withdraw:write. No response body.", + content = [Content()] + ) ] ) suspend fun verifyOTP( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "withdrawUuid", description = "Withdraw UUID.", required = true) @PathVariable withdrawUuid: String, + @Parameter(name = "otpType", description = "OTP delivery type. Allowed values: SMS, EMAIL.", required = true) @PathVariable otpType: OTPType, - @RequestParam otpCode: String, + @Parameter(name = "otpCode", description = "OTP code received by user.", required = true) + @RequestParam otpCode: String ): WithdrawActionResult { return walletProxy.verifyWithdrawOTP( securityContext.jwtAuthentication().tokenValue(), @@ -139,4 +241,4 @@ class WithdrawController( otpCode ) } -} \ No newline at end of file +} From a02d309776017abbe756d7dcedfbf770ce572373 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:13:04 +0330 Subject: [PATCH 42/56] Update swagger data about bank account services --- .../ports/opex/controller/BankAccountController.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt index 93e159b19..0d9b8140d 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/BankAccountController.kt @@ -30,7 +30,9 @@ class BankAccountController( description = """POST /opex/v1/bank-account. Security: Bearer user-token required. Requires authenticated user JWT. -Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid.""", +Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing both or neither is invalid. +Allowed values: +- status: WAITING, VERIFIED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = BankAccountResponse::class))]), @@ -49,7 +51,9 @@ Validation: Exactly one of `cardNumber` or `iban` must be provided. Providing bo @Operation( summary = "Get bank accounts", description = """GET /opex/v1/bank-account. -Security: Bearer user-token required. Requires authenticated user JWT.""", +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- status: WAITING, VERIFIED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = BankAccountResponse::class)))]), @@ -67,7 +71,9 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", @Operation( summary = "Delete bank account", description = """DELETE /opex/v1/bank-account/{id}. -Security: Bearer user-token required. Required authority: PERM_bank_account:write.""", +Security: Bearer user-token required. Required authority: PERM_bank_account:write. +Allowed values: +- status: WAITING, VERIFIED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), From 1f33bd568f521a036766fd53a517879cd0a44b90 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:34:42 +0330 Subject: [PATCH 43/56] Update swagger data about general and user level config services --- .../opex/controller/ConfigAdminController.kt | 67 ++++++ .../ports/opex/controller/ConfigController.kt | 87 -------- .../opex/controller/UserConfigController.kt | 201 ++++++++++++++++++ .../controller/UserLevelAdminController.kt | 109 ++++++++++ .../opex/controller/UserLevelController.kt | 45 ++++ 5 files changed, 422 insertions(+), 87 deletions(-) create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigAdminController.kt delete mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserConfigController.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt create mode 100644 api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelController.kt diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigAdminController.kt new file mode 100644 index 000000000..31a2ee981 --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigAdminController.kt @@ -0,0 +1,67 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.UpdateUserConfigRequest +import co.nilin.opex.api.core.inout.UpdateWebConfigRequest +import co.nilin.opex.api.core.inout.UserWebConfig +import co.nilin.opex.api.core.spi.ConfigProxy +import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import co.nilin.opex.common.data.WebConfig +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/opex/v1") +@Tag( + name = "Admin Config", + description = "Default web and user configuration operations." +) +class ConfigAdminController(private val configProxy: ConfigProxy) { + + + @PutMapping("/admin/web/config") + @Operation( + summary = "Update web config", + description = """PUT /opex/v1/admin/web/config. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Allowed values: +- defaultLanguage/supportedLanguages: EN, FA, AR, UZ. +- supportedCalenders: JALALI, HIJRI, GREGORIAN. +- defaultTheme/supportedThemes: DARK, LIGHT, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content(mediaType = "application/json", schema = Schema(implementation = UpdateWebConfigRequest::class))] + ), + responses = [ + ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = WebConfig::class))]), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) + ] + ) + suspend fun updateWebConfig( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext, + @RequestBody request: UpdateWebConfigRequest + ): WebConfig { + return configProxy.updateWebConfig(securityContext.jwtAuthentication().tokenValue(), request) + } + +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt deleted file mode 100644 index c61b07fd2..000000000 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ConfigController.kt +++ /dev/null @@ -1,87 +0,0 @@ -package co.nilin.opex.api.ports.opex.controller - -import co.nilin.opex.api.core.inout.UpdateUserConfigRequest -import co.nilin.opex.api.core.inout.UpdateWebConfigRequest -import co.nilin.opex.api.core.inout.UserLevelConfig -import co.nilin.opex.api.core.inout.UserWebConfig -import co.nilin.opex.api.core.spi.ConfigProxy -import co.nilin.opex.api.ports.opex.util.jwtAuthentication -import co.nilin.opex.api.ports.opex.util.tokenValue -import co.nilin.opex.common.data.WebConfig -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* - -@RestController -@RequestMapping("/opex/v1") -class ConfigController(private val configProxy: ConfigProxy) { - - @GetMapping("/web/config") - suspend fun getWebConfig(): WebConfig { - return configProxy.getWebConfig() - } - - @PutMapping("/admin/web/config") - suspend fun updateWebConfig( - @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UpdateWebConfigRequest - ): WebConfig { - return configProxy.updateWebConfig(securityContext.jwtAuthentication().tokenValue(), request) - } - - @GetMapping("/user-level/config") - suspend fun getUserLevelConfig(): List { - return configProxy.getUserLevelConfig() - } - - @PutMapping("/admin/user-level/config") - suspend fun updateUserLevelConfig( - @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody userLevelConfig: UserLevelConfig - ): UserLevelConfig { - return configProxy.updateUserLevelConfig(securityContext.jwtAuthentication().tokenValue(), userLevelConfig) - } - - @DeleteMapping("/admin/user-level/config/{userLevel}/{language}") - suspend fun updateUserLevelConfig( - @CurrentSecurityContext securityContext: SecurityContext, - @PathVariable userLevel: String, - @PathVariable language: String - ) { - configProxy.deleteUserLevelConfig(securityContext.jwtAuthentication().tokenValue(), userLevel, language) - } - - @GetMapping("/user/config") - suspend fun getUserConfig(@CurrentSecurityContext securityContext: SecurityContext): UserWebConfig { - return configProxy.getUserConfig(securityContext.jwtAuthentication().tokenValue()) - } - - @PutMapping("/user/config") - suspend fun updateConfig( - @CurrentSecurityContext securityContext: SecurityContext, - @RequestBody request: UpdateUserConfigRequest - ): UserWebConfig { - return configProxy.updateUserConfig(securityContext.jwtAuthentication().tokenValue(), request) - } - - @GetMapping("/user/config/pair") - suspend fun getUserFavoritePair(@CurrentSecurityContext securityContext: SecurityContext): Set { - return configProxy.getUserFavoritePair(securityContext.jwtAuthentication().tokenValue()) - } - - @PostMapping("/user/config/pair/{pair}") - suspend fun addUserFavoritePair( - @CurrentSecurityContext securityContext: SecurityContext, - @PathVariable pair: String - ): Set { - return configProxy.addUserFavoritePair(securityContext.jwtAuthentication().tokenValue(), pair) - } - - @DeleteMapping("/user/config/pair/{pair}") - suspend fun removeUserFavoritePair( - @CurrentSecurityContext securityContext: SecurityContext, - @PathVariable pair: String - ): Set { - return configProxy.removeUserFavoritePair(securityContext.jwtAuthentication().tokenValue(), pair) - } -} \ No newline at end of file diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserConfigController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserConfigController.kt new file mode 100644 index 000000000..bf3fb1280 --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserConfigController.kt @@ -0,0 +1,201 @@ +package co.nilin.opex.api.ports.opex.controller + +import co.nilin.opex.api.core.inout.UpdateUserConfigRequest +import co.nilin.opex.api.core.inout.UserWebConfig +import co.nilin.opex.api.core.spi.ConfigProxy +import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import co.nilin.opex.common.data.WebConfig +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* + +@RestController +@RequestMapping("/opex/v1") +@Tag( + name = "Config", + description = "Web and user configuration operations." +) +class UserConfigController(private val configProxy: ConfigProxy) { + + @GetMapping("/web/config") + @Operation( + summary = "Get web config", + description = """GET /opex/v1/web/config. +Security: Public endpoint. No Bearer token is required. + +Allowed values: +- language: EN, FA, AR, UZ. +- calender: JALALI, HIJRI, GREGORIAN. +- theme: DARK, LIGHT, SYSTEM.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = WebConfig::class))] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun getWebConfig(): WebConfig { + return configProxy.getWebConfig() + } + + @GetMapping("/user/config") + @Operation( + summary = "Get user config", + description = """GET /opex/v1/user/config. +Security: Bearer user-token required. Requires authenticated user JWT. + +Allowed values: +- language: EN, FA, AR, UZ. +- calender: JALALI, HIJRI, GREGORIAN. +- theme: DARK, LIGHT, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = UserWebConfig::class) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun getUserConfig( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ): UserWebConfig { + return configProxy.getUserConfig(securityContext.jwtAuthentication().tokenValue()) + } + + @PutMapping("/user/config") + @Operation( + summary = "Update user config", + description = """PUT /opex/v1/user/config. +Security: Bearer user-token required. Requires authenticated user JWT. + +Allowed values: +- language: EN, FA, AR, UZ. +- calender: JALALI, HIJRI, GREGORIAN. +- theme: DARK, LIGHT, SYSTEM.""", + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = UpdateUserConfigRequest::class) + )] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = UserWebConfig::class) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun updateConfig( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext, + @RequestBody request: UpdateUserConfigRequest + ): UserWebConfig { + return configProxy.updateUserConfig(securityContext.jwtAuthentication().tokenValue(), request) + } + + @GetMapping("/user/config/pair") + @Operation( + summary = "Get favorite pairs", + description = """GET /opex/v1/user/config/pair. +Security: Bearer user-token required. Requires authenticated user JWT. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(type = "string")) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun getUserFavoritePair( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ): Set { + return configProxy.getUserFavoritePair(securityContext.jwtAuthentication().tokenValue()) + } + + @PostMapping("/user/config/pair/{pair}") + @Operation( + summary = "Add favorite pair", + description = """POST /opex/v1/user/config/pair/{pair}. +Security: Bearer user-token required. Requires authenticated user JWT. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(type = "string")) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun addUserFavoritePair( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "pair", description = "Market pair symbol.", required = true) + @PathVariable pair: String + ): Set { + return configProxy.addUserFavoritePair(securityContext.jwtAuthentication().tokenValue(), pair) + } + + @DeleteMapping("/user/config/pair/{pair}") + @Operation( + summary = "Remove favorite pair", + description = """DELETE /opex/v1/user/config/pair/{pair}. +Security: Bearer user-token required. Requires authenticated user JWT. +""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(type = "string")) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun removeUserFavoritePair( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "pair", description = "Market pair symbol.", required = true) + @PathVariable pair: String + ): Set { + return configProxy.removeUserFavoritePair(securityContext.jwtAuthentication().tokenValue(), pair) + } +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt new file mode 100644 index 000000000..2aeb21a42 --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt @@ -0,0 +1,109 @@ +package co.nilin.opex.api.ports.opex.controller; + +import co.nilin.opex.api.core.inout.UserLevelConfig +import co.nilin.opex.api.core.spi.ConfigProxy +import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* +@RestController +@RequestMapping("/opex/v1") +@Tag( + name = "Admin User Config", + description = "User level configuration operations." +) +public class UserLevelAdminController(private val configProxy: ConfigProxy) { + @GetMapping("/user-level/config") + @Operation( + summary = "Get user level config", + description = """GET /opex/v1/user-level/config. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = UserLevelConfig::class)) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun getUserLevelConfig(): List { + return configProxy.getUserLevelConfig() + } + + @PutMapping("/admin/user-level/config") + @Operation( + summary = "Update user level config", + description = """PUT /opex/v1/admin/user-level/config. +Security: Bearer admin-token required. Required authority: ROLE_admin.""", + security = [SecurityRequirement(name = "bearerAuth")], + requestBody = io.swagger.v3.oas.annotations.parameters.RequestBody( + required = true, + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = UserLevelConfig::class) + )] + ), + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = UserLevelConfig::class) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) + ] + ) + suspend fun updateUserLevelConfig( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext, + @RequestBody userLevelConfig: UserLevelConfig + ): UserLevelConfig { + return configProxy.updateUserLevelConfig(securityContext.jwtAuthentication().tokenValue(), userLevelConfig) + } + + @DeleteMapping("/admin/user-level/config/{userLevel}/{language}") + @Operation( + summary = "Delete user level config", + description = """DELETE /opex/v1/admin/user-level/config/{userLevel}/{language}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Allowed values: +- language: EN, FA, AR, UZ.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) + ] + ) + suspend fun deleteUserLevelConfig( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext, + @Parameter(name = "userLevel", description = "User level key.", required = true) + @PathVariable userLevel: String, + @Parameter(name = "language", description = "Language: EN, FA, AR, UZ.", required = true) + @PathVariable language: String + ) { + configProxy.deleteUserLevelConfig(securityContext.jwtAuthentication().tokenValue(), userLevel, language) + } +} diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelController.kt new file mode 100644 index 000000000..92f21c3fe --- /dev/null +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelController.kt @@ -0,0 +1,45 @@ +package co.nilin.opex.api.ports.opex.controller; + +import co.nilin.opex.api.core.inout.UserLevelConfig +import co.nilin.opex.api.core.spi.ConfigProxy +import co.nilin.opex.api.ports.opex.util.jwtAuthentication +import co.nilin.opex.api.ports.opex.util.tokenValue +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* +@RestController +@RequestMapping("/opex/v1") +@Tag( + name = "Use Level", + description = "Fetch user level config, public endpoint" +) +public class UserLevelController(private val configProxy: ConfigProxy) { + @GetMapping("/user-level/config") + @Operation( + summary = "Get user level config", + description = """GET /opex/v1/user-level/config. +Security: Public endpoint. No Bearer token is required.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = UserLevelConfig::class)) + )] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) + ] + ) + suspend fun getUserLevelConfig(): List { + return configProxy.getUserLevelConfig() + } +} From dc8416ffe54568f7ce0f48c4800cc75f1c0f7da8 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:36:11 +0330 Subject: [PATCH 44/56] Update swagger data about deposit admin services --- .../opex/api/ports/opex/controller/DepositAdminController.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt index 532d085dd..92628de81 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/DepositAdminController.kt @@ -28,7 +28,9 @@ class DepositAdminController( @Operation( summary = "Deposit manually", description = """POST /opex/v1/admin/deposit/manually/{amount}_{symbol}/{receiverUuid}. -Security: Bearer admin-token required. Required authority: ROLE_admin.""", +Security: Bearer admin-token required. Required authority: ROLE_admin. +Allowed values: +- receiverWalletType/sourceWalletType where used: MAIN, EXCHANGE, CASHOUT.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), From 8dcad5ef1d921a5d719ec6b94e8645c5c6a8ea52 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:37:27 +0330 Subject: [PATCH 45/56] Update swagger data about gateway admin services --- .../opex/controller/GatewayAdminController.kt | 84 ++++++++++++++----- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt index 83c16767e..ddf72c5b9 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/GatewayAdminController.kt @@ -12,13 +12,13 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.ExampleObject import io.swagger.v3.oas.annotations.media.Schema -import io.swagger.v3.oas.annotations.parameters.RequestBody as SwaggerRequestBody import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* +import io.swagger.v3.oas.annotations.parameters.RequestBody as SwaggerRequestBody @RestController @RequestMapping("/opex/v1/admin") @@ -156,7 +156,8 @@ Response body: CurrencyGatewayCommand. discriminatorProperty = "type" ), examples = [ - ExampleObject(name = "OffChain gateway response", value = """ + ExampleObject( + name = "OffChain gateway response", value = """ { "type": "OffChain", "currencySymbol": "IRT", @@ -175,8 +176,10 @@ Response body: CurrencyGatewayCommand. "displayOrder": 1, "transferMethod": "CARD" } - """), - ExampleObject(name = "OnChain native gateway response", value = """ + """ + ), + ExampleObject( + name = "OnChain native gateway response", value = """ { "type": "OnChain", "currencySymbol": "BTC", @@ -200,8 +203,10 @@ Response body: CurrencyGatewayCommand. "decimal": 8, "chain": "bitcoin" } - """), - ExampleObject(name = "OnChain token gateway response", value = """ + """ + ), + ExampleObject( + name = "OnChain token gateway response", value = """ { "type": "OnChain", "currencySymbol": "USDT", @@ -225,7 +230,8 @@ Response body: CurrencyGatewayCommand. "decimal": 6, "chain": "tron" } - """) + """ + ) ] ) ] @@ -269,9 +275,13 @@ Response body: CurrencyGatewayCommand. content = [ Content( mediaType = "application/json", - schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"), + schema = Schema( + oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], + discriminatorProperty = "type" + ), examples = [ - ExampleObject(name = "OffChain gateway", summary = "OffChainGatewayCommand", value = """ + ExampleObject( + name = "OffChain gateway", summary = "OffChainGatewayCommand", value = """ { "type": "OffChain", "currencySymbol": "IRT", @@ -290,8 +300,12 @@ Response body: CurrencyGatewayCommand. "displayOrder": 1, "transferMethod": "CARD" } - """), - ExampleObject(name = "OnChain native gateway", summary = "OnChainGatewayCommand with isToken=false", value = """ + """ + ), + ExampleObject( + name = "OnChain native gateway", + summary = "OnChainGatewayCommand with isToken=false", + value = """ { "type": "OnChain", "currencySymbol": "BTC", @@ -315,8 +329,12 @@ Response body: CurrencyGatewayCommand. "decimal": 8, "chain": "bitcoin" } - """), - ExampleObject(name = "OnChain token gateway", summary = "OnChainGatewayCommand with isToken=true", value = """ + """ + ), + ExampleObject( + name = "OnChain token gateway", + summary = "OnChainGatewayCommand with isToken=true", + value = """ { "type": "OnChain", "currencySymbol": "USDT", @@ -340,7 +358,8 @@ Response body: CurrencyGatewayCommand. "decimal": 6, "chain": "tron" } - """) + """ + ) ] ) ] @@ -349,7 +368,13 @@ Response body: CurrencyGatewayCommand. ApiResponse( responseCode = "200", description = "Gateway updated successfully.", - content = [Content(mediaType = "application/json", schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"))] + content = [Content( + mediaType = "application/json", + schema = Schema( + oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], + discriminatorProperty = "type" + ) + )] ), ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) @@ -391,9 +416,13 @@ Response body: CurrencyGatewayCommand. content = [ Content( mediaType = "application/json", - schema = Schema(oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], discriminatorProperty = "type"), + schema = Schema( + oneOf = [OffChainGatewayCommand::class, OnChainGatewayCommand::class], + discriminatorProperty = "type" + ), examples = [ - ExampleObject(name = "OffChain gateway response", value = """ + ExampleObject( + name = "OffChain gateway response", value = """ { "type": "OffChain", "currencySymbol": "IRT", @@ -412,8 +441,10 @@ Response body: CurrencyGatewayCommand. "displayOrder": 1, "transferMethod": "CARD" } - """), - ExampleObject(name = "OnChain native gateway response", value = """ + """ + ), + ExampleObject( + name = "OnChain native gateway response", value = """ { "type": "OnChain", "currencySymbol": "BTC", @@ -437,8 +468,10 @@ Response body: CurrencyGatewayCommand. "decimal": 8, "chain": "bitcoin" } - """), - ExampleObject(name = "OnChain token gateway response", value = """ + """ + ), + ExampleObject( + name = "OnChain token gateway response", value = """ { "type": "OnChain", "currencySymbol": "USDT", @@ -462,7 +495,8 @@ Response body: CurrencyGatewayCommand. "decimal": 6, "chain": "tron" } - """) + """ + ) ] ) ] @@ -496,7 +530,11 @@ Response body: No response body. """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Gateway deleted successfully. No response body.", content = [Content()]), + ApiResponse( + responseCode = "200", + description = "Gateway deleted successfully. No response body.", + content = [Content()] + ), ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]), ApiResponse(responseCode = "403", description = "Forbidden. No response body.", content = [Content()]) ] From 9892e19ca4b94ed200719b678f15df065b74e876 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:47:35 +0330 Subject: [PATCH 46/56] Apply the kotlin style on profile services --- .../ports/opex/controller/OrderController.kt | 9 +- .../opex/controller/ProfileAdminController.kt | 6 +- .../opex/controller/ProfileController.kt | 113 ++++++++++++++---- 3 files changed, 100 insertions(+), 28 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt index aa74d899d..fc80f91ed 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/OrderController.kt @@ -259,7 +259,8 @@ Response body: @CurrentSecurityContext securityContext: SecurityContext ): CancelOrderResponse { if (orderId == null && origClientOrderId == null) throw OpexError.BadRequest.exception("'orderId' or 'origClientOrderId' must be sent") - val order = queryHandler.queryOrder(principal, symbol, orderId, origClientOrderId) ?: throw OpexError.OrderNotFound.exception() + val order = queryHandler.queryOrder(principal, symbol, orderId, origClientOrderId) + ?: throw OpexError.OrderNotFound.exception() val response = CancelOrderResponse( symbol, origClientOrderId, @@ -432,30 +433,36 @@ Response body: checkDecimal(quantity, "quantity") checkNull(timeInForce, "timeInForce") } + OrderType.MARKET -> { if (quantity == null) checkDecimal(quoteOrderQty, "quoteOrderQty") else checkDecimal(quantity, "quantity") } + OrderType.STOP_LOSS -> { checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") } + OrderType.STOP_LOSS_LIMIT -> { checkDecimal(price, "price") checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") checkNull(timeInForce, "timeInForce") } + OrderType.TAKE_PROFIT -> { checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") } + OrderType.TAKE_PROFIT_LIMIT -> { checkDecimal(price, "price") checkDecimal(quantity, "quantity") checkDecimal(stopPrice, "stopPrice") checkNull(timeInForce, "timeInForce") } + OrderType.LIMIT_MAKER -> { checkDecimal(price, "price") checkDecimal(quantity, "quantity") diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt index 41463a4d3..956bf60ba 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileAdminController.kt @@ -4,9 +4,6 @@ import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.core.spi.ProfileProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.ArraySchema @@ -15,6 +12,9 @@ import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/admin/profile") diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt index 816f3ba16..6ee993593 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/ProfileController.kt @@ -6,22 +6,24 @@ import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.toProfileApprovalRequestUserResponse import co.nilin.opex.api.ports.opex.util.toProfileResponse import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/profile") -@Tag(name = "Profile", description = "Authenticated user profile operations.") +@Tag( + name = "Profile", + description = "Authenticated user profile operations." +) class ProfileController( val profileProxy: ProfileProxy ) { @@ -30,15 +32,32 @@ class ProfileController( @Operation( summary = "Get profile", description = """GET /opex/v1/profile/personal-data. -Security: Bearer user-token required. Requires authenticated user JWT.""", +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ProfileResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) - suspend fun getProfile(@Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext): ProfileResponse { + suspend fun getProfile( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ): ProfileResponse { return profileProxy.getProfile(securityContext.jwtAuthentication().tokenValue()).toProfileResponse() } @@ -46,11 +65,26 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", @Operation( summary = "Complete profile", description = """PUT /opex/v1/profile/completion. -Security: Bearer user-token required. Requires authenticated user JWT.""", +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ProfileResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) suspend fun completeProfile( @@ -68,13 +102,22 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", description = """POST /opex/v1/profile/contact/update/otp-request. Behavior: Starts contact update flow and returns OTP delivery information. Security: Bearer user-token required. Requires authenticated user JWT. -Validation: Exactly one of `mobile` or `email` must be provided. Providing both or neither is invalid. """, - security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TempOtpResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = TempOtpResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) suspend fun requestContactUpdate( @@ -90,11 +133,16 @@ Validation: Exactly one of `mobile` or `email` must be provided. Providing both summary = "Confirm contact update", description = """PATCH /opex/v1/profile/contact/update/otp-verification. Validation: Verification request must contain the OTP value and target contact details required by the request schema. -Security: Bearer user-token required. Requires authenticated user JWT.""", +Security: Bearer user-token required. Requires authenticated user JWT. +""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) suspend fun confirmContactUpdate( @@ -110,15 +158,32 @@ Security: Bearer user-token required. Requires authenticated user JWT.""", @Operation( summary = "Get approval request", description = """GET /opex/v1/profile/approval-request. -Security: Bearer user-token required. Requires authenticated user JWT.""", +Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- nationality: IRANIAN, NON_IRANIAN. +- gender: FEMALE, MALE. +- approval request status: PENDING, APPROVED, REJECTED.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ProfileApprovalRequestUserResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ProfileApprovalRequestUserResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) - suspend fun getApprovalRequest(@Parameter(hidden = true) - @CurrentSecurityContext securityContext: SecurityContext): ProfileApprovalRequestUserResponse { + suspend fun getApprovalRequest( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ): ProfileApprovalRequestUserResponse { return profileProxy.getUserProfileApprovalRequest(securityContext.jwtAuthentication().tokenValue()) .toProfileApprovalRequestUserResponse() } From 635243e5526cea147dc7955e670de7209e34e6f4 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:54:37 +0330 Subject: [PATCH 47/56] Apply the kotlin style on storage services --- .../opex/controller/StorageAdminController.kt | 51 ++++++++++++++----- .../opex/controller/StorageController.kt | 21 +++++--- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt index 49ec65e6e..bd0484223 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageAdminController.kt @@ -3,12 +3,6 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.spi.StorageProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.beans.factory.annotation.Value -import org.springframework.http.ResponseEntity -import org.springframework.http.codec.multipart.FilePart -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.Content @@ -16,7 +10,13 @@ import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.beans.factory.annotation.Value import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.http.codec.multipart.FilePart +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* @Schema(name = "StorageUploadMultipartRequest") @@ -44,12 +44,28 @@ class StorageAdminController( description = """GET /opex/v1/admin/storage. Behavior: Returns binary file bytes for the requested bucket/key. Security: Bearer admin-token required. Required authority: ROLE_admin. -""", +Allowed values: +- isPublic: true, false.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/octet-stream", schema = Schema(type = "string", format = "binary"))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/octet-stream", + schema = Schema(type = "string", format = "binary") + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun download( @@ -161,12 +177,21 @@ Allowed values: description = """DELETE /opex/v1/admin/storage. Behavior: Deletes the object identified by bucket/key. Response has no body. Security: Bearer admin-token required. Required authority: ROLE_admin. -""", +Allowed values: +- isPublic: true, false.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun delete( diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt index 70e056fe5..04d4e8c54 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/StorageController.kt @@ -1,19 +1,17 @@ package co.nilin.opex.api.ports.opex.controller import co.nilin.opex.api.core.spi.StorageProxy -import org.springframework.http.ResponseEntity -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RequestParam -import org.springframework.web.bind.annotation.RestController import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse -import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/opex/v1/storage") @@ -29,7 +27,14 @@ Behavior: Public file download for the requested bucket/key. Returns binary file Security: Public endpoint. No Bearer token is required. """, responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/octet-stream", schema = Schema(type = "string", format = "binary"))]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/octet-stream", + schema = Schema(type = "string", format = "binary") + )] + ) ] ) suspend fun download( From 22a818597364938c6a63fe74ffe7fd38250c7008 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 17:56:03 +0330 Subject: [PATCH 48/56] Update swagger data about swap services --- .../ports/opex/controller/SwapController.kt | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt index b26e6cbbe..52b2779fc 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/SwapController.kt @@ -6,17 +6,16 @@ import co.nilin.opex.api.core.inout.TransferResult import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter -import io.swagger.v3.oas.annotations.media.ArraySchema import io.swagger.v3.oas.annotations.media.Content import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/swap") @@ -29,12 +28,25 @@ class SwapController( summary = "Reserve", description = """POST /opex/v1/swap/reserve. Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- sourceWalletType and destWalletType where used: MAIN, EXCHANGE, CASHOUT. Source of values: - sourceSymbol and destSymbol are server-provided currency symbols.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = ReservedTransferResponse::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ReservedTransferResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) suspend fun reserve( @@ -51,16 +63,33 @@ Source of values: description = """POST /opex/v1/swap/finalize/{reserveUuid}. Behavior: `description` and `transferRef` are optional metadata for finalizing a reserved swap. Security: Bearer user-token required. Requires authenticated user JWT. +Allowed values: +- sourceWalletType and destWalletType where used: MAIN, EXCHANGE, CASHOUT. Source of values: - sourceSymbol and destSymbol are server-provided currency symbols.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TransferResult::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = TransferResult::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) ] ) suspend fun finalizeTransfer( - @Parameter(name = "reserveUuid", description = "Swap reserve UUID returned by reserve endpoint.", required = true) + @Parameter( + name = "reserveUuid", + description = "Swap reserve UUID returned by reserve endpoint.", + required = true + ) @PathVariable reserveUuid: String, @Parameter(name = "description", description = "Optional transfer description.", required = false) @RequestParam description: String?, From 885bd248aefe8421e481914a1403e22d05bbefa8 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 18:00:58 +0330 Subject: [PATCH 49/56] Apply the kotlin style on terminal and tx services --- .../controller/TerminalAdminController.kt | 147 +++++++++++++++--- .../controller/TransactionAdminController.kt | 12 +- 2 files changed, 129 insertions(+), 30 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt index 905e23bce..09cc709e7 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TerminalAdminController.kt @@ -6,9 +6,6 @@ import co.nilin.opex.api.core.inout.TerminalUpdateCommand import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.ArraySchema @@ -17,6 +14,9 @@ import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/opex/v1/admin/terminal") @@ -32,9 +32,24 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalCommand::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = TerminalCommand::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun registerTerminal( @@ -53,9 +68,24 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalCommand::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = TerminalCommand::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun updateTerminal( @@ -77,8 +107,16 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun deleteTerminal( @@ -98,9 +136,24 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = TerminalCommand::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getTerminal( @@ -118,9 +171,24 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", schema = Schema(implementation = TerminalCommand::class))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = TerminalCommand::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getTerminal( @@ -140,9 +208,24 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. """, security = [SecurityRequirement(name = "bearerAuth")], responses = [ - ApiResponse(responseCode = "200", description = "Successful response.", content = [Content(mediaType = "application/json", array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)))]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = CurrencyGatewayCommand::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun getGatewayTerminal( @@ -165,8 +248,16 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun assignTerminalToGateway( @@ -193,8 +284,16 @@ Security: Bearer admin-token required. Required authority: ROLE_admin. security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse(responseCode = "200", description = "No response body.", content = [Content()]), - ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), - ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) ] ) suspend fun revokeTerminalFromGateway( diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt index 20ff066cc..d28fb924a 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/TransactionAdminController.kt @@ -4,12 +4,6 @@ import co.nilin.opex.api.core.inout.* import co.nilin.opex.api.core.spi.WalletProxy import co.nilin.opex.api.ports.opex.util.jwtAuthentication import co.nilin.opex.api.ports.opex.util.tokenValue -import org.springframework.security.core.annotation.CurrentSecurityContext -import org.springframework.security.core.context.SecurityContext -import org.springframework.web.bind.annotation.PostMapping -import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.media.ArraySchema @@ -18,6 +12,12 @@ import io.swagger.v3.oas.annotations.media.Schema import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.security.core.annotation.CurrentSecurityContext +import org.springframework.security.core.context.SecurityContext +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController From 844e7fe4166d566a20a49df53b29618e1b23e369 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Thu, 28 May 2026 18:02:57 +0330 Subject: [PATCH 50/56] Update swagger data about user data services --- .../controller/UserAnalyticsController.kt | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt index 4d5d6433a..5a0fe2e95 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserAnalyticsController.kt @@ -38,37 +38,34 @@ class UserAnalyticsController( summary = "User activity", description = """GET /opex/v1/analytics/user-activity. Security: Bearer user-token required. Requires authenticated user JWT. -""", + +Behavior: +- Returns activity totals for the last 31 days. +- Response object keys are epoch timestamps in milliseconds. +- All date/time values exposed by the API layer are timestamps.""", security = [SecurityRequirement(name = "bearerAuth")], responses = [ ApiResponse( responseCode = "200", - description = "Successful response.", - content = [ - Content( - mediaType = "application/json", - schema = Schema( - type = "object", - additionalPropertiesSchema = ActivityTotals::class - ), - examples = [ - ExampleObject( - name = "User activity response", - value = """ + description = "Successful response. Map key is epoch timestamp in milliseconds. Map value is daily activity totals.", + content = [Content( + mediaType = "application/json", + schema = Schema(type = "object", additionalPropertiesSchema = ActivityTotals::class), + examples = [ExampleObject( + name = "User activity response", + value = """ { - "1715817600000": { - "totalBalance": 1200.00, - "totalWithdraw": 0, - "totalDeposit": 100.00, - "totalTrade": 300.00, - "totalOrder": 5 + "1715731200000": { + "totalBalance": 1000.50, + "totalWithdraw": 20.00, + "totalDeposit": 200.00, + "totalTrade": 150.00, + "totalOrder": 3 } } - """ - ) - ] - ) - ] + """ + )] + )] ), ApiResponse( responseCode = "401", @@ -90,6 +87,11 @@ Security: Bearer user-token required. Requires authenticated user JWT. summary = "Get user details assets", description = """GET /opex/v1/analytics/users-detail-assets. Security: Public endpoint. No Bearer token is required. + +Behavior: +- limit defaults to 10 when omitted. +- offset defaults to 0 when omitted. + """, responses = [ ApiResponse( From 1ea15caed52d11371bc0432cca75f7f0218ad5ea Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Fri, 29 May 2026 17:00:49 +0330 Subject: [PATCH 51/56] Develop a swagger service to merge api and auth swagger data on a single page --- .../opex/api/app/config/OpenApiConfig.kt | 4 +- .../opex/api/app/config/OpenApiCorsConfig.kt | 46 ++++ .../api/app/controller/APIKeyController.kt | 215 +++++++++++++++++- .../api/app/controller/RateLimitController.kt | 29 ++- .../src/main/resources/application.yml | 8 +- .../ports/binance/config/SecurityConfig.kt | 1 + .../controller/UserLevelAdminController.kt | 21 -- .../opex/controller/VoucherController.kt | 2 +- .../opex/controller/WalletAdminController.kt | 2 +- .../ports/opex/controller/WalletController.kt | 2 +- .../controller/WithdrawAdminController.kt | 2 +- auth-gateway/auth-gateway-app/pom.xml | 5 + .../nilin/opex/auth/config/OpenApiConfig.kt | 36 +++ .../opex/auth/config/OpenApiCorsConfig.kt | 46 ++++ .../nilin/opex/auth/config/SecurityConfig.kt | 72 ++++-- .../opex/auth/controller/AuthController.kt | 99 +++++++- .../auth/controller/PublicUserController.kt | 129 ++++++++++- .../opex/auth/controller/SessionController.kt | 155 ++++++++++++- .../kotlin/co/nilin/opex/auth/model/OTP.kt | 1 - .../src/main/resources/application.yml | 12 +- docker-compose.yml | 31 +++ 21 files changed, 837 insertions(+), 81 deletions(-) create mode 100644 api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiCorsConfig.kt create mode 100644 auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt create mode 100644 auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiCorsConfig.kt diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt index b5713baec..ac4597ed7 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt @@ -4,11 +4,13 @@ import io.swagger.v3.oas.models.Components import io.swagger.v3.oas.models.OpenAPI import io.swagger.v3.oas.models.info.Info import io.swagger.v3.oas.models.security.SecurityScheme +import io.swagger.v3.oas.models.servers.Server +import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration -class OpenApiConfig { +class OpenApiConfig() { @Bean fun opexOpenApi(): OpenAPI { diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiCorsConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiCorsConfig.kt new file mode 100644 index 000000000..02150efcf --- /dev/null +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiCorsConfig.kt @@ -0,0 +1,46 @@ +package co.nilin.opex.api.app.config + +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.Ordered +import org.springframework.core.annotation.Order +import org.springframework.web.cors.CorsConfiguration +import org.springframework.web.cors.reactive.CorsWebFilter +import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource + +@Configuration(proxyBeanMethods = false) +class OpenApiCorsConfig( + @Value("\${app.swagger.cors.enabled:false}") + private val enabled: Boolean, + + @Value("\${app.swagger.cors.allowed-origins:http://localhost:8110}") + private val allowedOrigins: String +) { + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + fun swaggerCorsWebFilter(): CorsWebFilter { + val config = CorsConfiguration().apply { + allowedOrigins = if (enabled) { + this@OpenApiCorsConfig.allowedOrigins + .split(",") + .map { it.trim() } + .filter { it.isNotBlank() } + } else { + emptyList() + } + + allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS") + allowedHeaders = listOf("*") + exposedHeaders = listOf("Location", "Content-Disposition") + allowCredentials = false + maxAge = 3600 + } + + val source = UrlBasedCorsConfigurationSource() + source.registerCorsConfiguration("/**", config) + + return CorsWebFilter(source) + } +} \ No newline at end of file diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/APIKeyController.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/APIKeyController.kt index 04e566341..5bf8beadf 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/APIKeyController.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/APIKeyController.kt @@ -4,16 +4,28 @@ import co.nilin.opex.api.app.data.ApiKeyResponse import co.nilin.opex.api.app.data.CreateApiKeyRequest import co.nilin.opex.api.app.data.UpdateApiKeyRequest import co.nilin.opex.common.security.JwtUtils +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.web.bind.annotation.* import java.security.SecureRandom import java.util.* @RestController @RequestMapping("/v1/api-key") +@Tag( + name = "API App - API Keys", + description = "API key management operations." +) class APIKeyController( private val apiKeyService: co.nilin.opex.api.core.spi.APIKeyService ) { - private val rng = SecureRandom() private fun generateSecretBase64(bytes: Int = 48): String { @@ -31,16 +43,40 @@ class APIKeyController( "X-API-BODY-SHA256" to " (optional)" ) - // Create a new API key. Caller must provide a user access token; we bind the key to that user. Returns one-time secret and usage hints. @PostMapping + @Operation( + summary = "Create API key", + description = """POST /v1/api-key. +Security: Bearer user-token required. + +Behavior: Creates a new API key for the authenticated user. The generated secret is returned only once in this response. +Source of values: Use the Bearer token of the user who should own the API key.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ApiKeyResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun create( - @RequestHeader(name = "Authorization", required = false) authorization: String?, + @Parameter(hidden = true) + @RequestHeader(name = "Authorization", required = false) + authorization: String?, @RequestBody req: CreateApiKeyRequest ): ApiKeyResponse { require(!authorization.isNullOrBlank() && authorization.startsWith("Bearer ")) { "Authorization Bearer user token is required" } val userToken = authorization.substringAfter("Bearer ").trim() val (userId, preferredUsername) = parseJwtUser(userToken) - val apiKeyId = req.apiKeyId?.takeIf { it.isNotBlank() } ?: UUID.randomUUID().toString() val secret = generateSecretBase64() val stored = apiKeyService.createApiKeyRecord( @@ -65,7 +101,6 @@ class APIKeyController( } private fun parseJwtUser(token: String): Pair { - // Decode JWT payload using common JwtUtils (no signature verification here). val payload = JwtUtils.decodePayload(token) val sub = payload["sub"] as? String val preferred = payload["username"] as? String @@ -73,8 +108,35 @@ class APIKeyController( return Pair(sub!!, preferred) } - // List all API keys (admin-only) — secret is not returned @GetMapping + @Operation( + summary = "List API keys", + description = """GET /v1/api-key. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Returns API key metadata. Secrets are not returned.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = ApiKeyResponse::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun list(): List = apiKeyService.listApiKeyRecords().stream().map { ApiKeyResponse( apiKeyId = it.apiKeyId, @@ -87,9 +149,41 @@ class APIKeyController( ) }.toList() - - // Get one API key (admin-only) — secret is not returned @GetMapping("/{apiKeyId}") + @Operation( + summary = "Get API key", + description = """GET /v1/api-key/{apiKeyId}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Returns API key metadata. Secret is not returned.""", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [Parameter( + name = "apiKeyId", + `in` = ParameterIn.PATH, + required = true, + description = "API key id." + )], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ApiKeyResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun get(@PathVariable apiKeyId: String): ApiKeyResponse { val it = apiKeyService.getApiKeyRecord(apiKeyId) ?: throw NoSuchElementException("API key not found: $apiKeyId") return ApiKeyResponse( @@ -103,8 +197,41 @@ class APIKeyController( ) } - // Rotate secret (admin-only). Returns new one-time secret @PostMapping("/{apiKeyId}/rotate") + @Operation( + summary = "Rotate API key secret", + description = """POST /v1/api-key/{apiKeyId}/rotate. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Rotates the API key secret. The new secret is returned only once in this response.""", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [Parameter( + name = "apiKeyId", + `in` = ParameterIn.PATH, + required = true, + description = "API key id." + )], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ApiKeyResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun rotate(@PathVariable apiKeyId: String): ApiKeyResponse { val newSecret = generateSecretBase64() val stored = apiKeyService.rotateApiKeySecret(apiKeyId, newSecret) @@ -119,8 +246,41 @@ class APIKeyController( ) } - // Update metadata or enable/disable (admin-only) @PutMapping("/{apiKeyId}") + @Operation( + summary = "Update API key", + description = """PUT /v1/api-key/{apiKeyId}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Updates API key metadata and enabled status. Secret is not returned.""", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [Parameter( + name = "apiKeyId", + `in` = ParameterIn.PATH, + required = true, + description = "API key id." + )], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = ApiKeyResponse::class) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun update(@PathVariable apiKeyId: String, @RequestBody req: UpdateApiKeyRequest): ApiKeyResponse { val s = apiKeyService.updateApiKeyRecord( apiKeyId = apiKeyId, @@ -140,9 +300,40 @@ class APIKeyController( ) } - // Delete/revoke (admin-only) @DeleteMapping("/{apiKeyId}") + @Operation( + summary = "Delete API key", + description = """DELETE /v1/api-key/{apiKeyId}. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Deletes or revokes the API key. +Response body: No response body.""", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [Parameter( + name = "apiKeyId", + `in` = ParameterIn.PATH, + required = true, + description = "API key id." + )], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "403", + description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", + content = [Content()] + ) + ] + ) suspend fun delete(@PathVariable apiKeyId: String) { apiKeyService.deleteApiKeyRecord(apiKeyId) } -} \ No newline at end of file +} diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/RateLimitController.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/RateLimitController.kt index e4a8f679c..b029997e1 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/RateLimitController.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/controller/RateLimitController.kt @@ -1,17 +1,42 @@ package co.nilin.opex.api.app.controller import co.nilin.opex.api.core.spi.RateLimitConfigService +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/v1/rate-limit") +@Tag( + name = "API App - Rate Limit", + description = "Rate-limit administration operations." +) class RateLimitController( private val rateLimitConfig: RateLimitConfigService, ) { - @PostMapping + + @GetMapping + @Operation( + summary = "Reload rate-limit config", + description = """POST /v1/rate-limit. +Security: Bearer admin-token required. Required authority: ROLE_admin. + +Behavior: Reloads rate-limit configuration from the configured source. +Response body: No response body.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse(responseCode = "200", description = "Successful response. No response body.", content = [Content()]), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]), + ApiResponse(responseCode = "403", description = "Forbidden. Required authority is missing: ROLE_admin. No response body.", content = [Content()]) + ] + ) suspend fun reloadRateLimits() { rateLimitConfig.loadConfig() } -} \ No newline at end of file +} diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index bba9e1cce..353f13cc1 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -149,14 +149,16 @@ app: api: crypto: key: ${api_crypto_key:0e1fd29572ec8c85970d76e3433e96ee} - + swagger: + cors: + enabled: true + allowed-origins: "http://localhost:8110" # --- Swagger / SpringDoc (env-driven) --- springdoc: api-docs: enabled: ${SWAGGER_API_DOCS_ENABLED:false} path: ${SWAGGER_API_DOCS_PATH:/v3/api-docs} - swagger-ui: enabled: ${SWAGGER_UI_ENABLED:false} path: ${SWAGGER_UI_PATH:/swagger-ui.html} @@ -165,4 +167,4 @@ springdoc: display-request-duration: true operations-sorter: method tags-sorter: alpha -spring.mvc.pathmatch.matching-strategy: ANT_PATH_MATCHER + diff --git a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt index be0aa9ebd..3b3996a19 100644 --- a/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt +++ b/api/api-ports/api-binance-rest/src/main/kotlin/co/nilin/opex/api/ports/binance/config/SecurityConfig.kt @@ -71,6 +71,7 @@ class SecurityConfig( return http.csrf { it.disable() } .authorizeExchange { it.pathMatchers("/actuator/**").permitAll() + .pathMatchers(HttpMethod.OPTIONS, "/**").permitAll() .pathMatchers("/v1/rate-limit").hasAuthority("ROLE_admin") .pathMatchers("/v2/api-docs").permitAll() .pathMatchers("/v3/depth").permitAll() diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt index 2aeb21a42..79a8dfffe 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/UserLevelAdminController.kt @@ -22,27 +22,6 @@ import org.springframework.web.bind.annotation.* description = "User level configuration operations." ) public class UserLevelAdminController(private val configProxy: ConfigProxy) { - @GetMapping("/user-level/config") - @Operation( - summary = "Get user level config", - description = """GET /opex/v1/user-level/config. -Security: Public endpoint. No Bearer token is required.""", - responses = [ - ApiResponse( - responseCode = "200", - description = "Successful response.", - content = [Content( - mediaType = "application/json", - array = ArraySchema(schema = Schema(implementation = UserLevelConfig::class)) - )] - ), - ApiResponse(responseCode = "401", description = "Unauthorized. No response body.", content = [Content()]) - ] - ) - suspend fun getUserLevelConfig(): List { - return configProxy.getUserLevelConfig() - } - @PutMapping("/admin/user-level/config") @Operation( summary = "Update user level config", diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt index 7489938f3..f0e6ec518 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/VoucherController.kt @@ -22,7 +22,7 @@ import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/voucher") -@Tag(name = "Voucher", description = "Authenticated voucher submission operations.\n\nSource of values:\n- code is a server-issued voucher code.") +@Tag(name = "Voucher", description = "Authenticated voucher submission operations.") class VoucherController(private val walletProxy: WalletProxy) { @PutMapping("/{code}") diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt index 93f434c3d..cb5412c45 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletAdminController.kt @@ -22,7 +22,7 @@ import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/wallet") -@Tag(name = "Wallet Admin", description = "Admin wallet overview and total balance operations.\n\nSource of values:\n- currency is a server-provided currency symbol.\nAllowed values:\n- excludeSystem: true, false.") +@Tag(name = "Wallet Admin", description = "Admin wallet overview and total balance operations.") class WalletAdminController( private val walletProxy: WalletProxy ) { diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt index b2c546c4f..f5ccedebd 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WalletController.kt @@ -26,7 +26,7 @@ import io.swagger.v3.oas.annotations.tags.Tag @RestController("walletOpexController") @RequestMapping("/opex/v1/wallet") -@Tag(name = "Wallet", description = "Authenticated user wallet asset, limits, and deposit address operations.\n\nAllowed values:\n- walletType values in related wallet responses/requests: MAIN, EXCHANGE, CASHOUT.\nSource of values:\n- symbol, currency and gatewayUuid are server-provided values.") +@Tag(name = "Wallet", description = "Authenticated user wallet asset, limits, and deposit address operations.") class WalletController( private val walletProxy: WalletProxy, private val bcGatewayProxy: BlockchainGatewayProxy diff --git a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt index 50f1de903..8a902b4e8 100644 --- a/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt +++ b/api/api-ports/api-opex-rest/src/main/kotlin/co/nilin/opex/api/ports/opex/controller/WithdrawAdminController.kt @@ -19,7 +19,7 @@ import io.swagger.v3.oas.annotations.tags.Tag @RestController @RequestMapping("/opex/v1/admin/withdraw") -@Tag(name = "Withdraw Admin", description = "Admin manual withdraw and withdraw workflow operations.\n\nAllowed values:\n- withdraw status: REQUESTED, CREATED, ACCEPTED, CANCELED, REJECTED, DONE.\n- withdrawType: CARD_TO_CARD, SHEBA, ON_CHAIN, OFF_CHAIN.\n- transferMethod: CARD, SHEBA, IPG, EXCHANGE, MANUALLY, VOUCHER, MPG, REWARD.\n- sourceWalletType where used: MAIN, EXCHANGE, CASHOUT.") +@Tag(name = "Withdraw Admin", description = "Admin manual withdraw and withdraw workflow operations.") class WithdrawAdminController( private val walletProxy: WalletProxy ) { diff --git a/auth-gateway/auth-gateway-app/pom.xml b/auth-gateway/auth-gateway-app/pom.xml index 0ff3a5ade..1be88098a 100644 --- a/auth-gateway/auth-gateway-app/pom.xml +++ b/auth-gateway/auth-gateway-app/pom.xml @@ -129,6 +129,11 @@ micrometer-registry-prometheus runtime + + org.springdoc + springdoc-openapi-starter-webflux-api + 2.6.0 + diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt new file mode 100644 index 000000000..f736645e7 --- /dev/null +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt @@ -0,0 +1,36 @@ +package co.nilin.opex.auth.config + +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.security.SecurityScheme +import io.swagger.v3.oas.models.servers.Server +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration(proxyBeanMethods = false) +class AuthGatewayOpenApiConfig() { + + @Bean + fun authGatewayOpenApi(): OpenAPI { + return OpenAPI() + .info( + Info() + .title("Opex Auth Gateway API") + .description("OpenAPI documentation for Opex Auth Gateway APIs.") + .version("1.0.1-beta.7") + .description("Backend for opex exchange.") + ) + .components( + Components().addSecuritySchemes( + "bearerAuth", + SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .description("JWT Bearer token") + ) + ) + } +} diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiCorsConfig.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiCorsConfig.kt new file mode 100644 index 000000000..5c31a0c2c --- /dev/null +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiCorsConfig.kt @@ -0,0 +1,46 @@ +package co.nilin.opex.auth.config + +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.Ordered +import org.springframework.core.annotation.Order +import org.springframework.web.cors.CorsConfiguration +import org.springframework.web.cors.reactive.CorsWebFilter +import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource + +@Configuration(proxyBeanMethods = false) +class OpenApiCorsConfig( + @Value("\${app.swagger.cors.enabled:false}") + private val enabled: Boolean, + + @Value("\${app.swagger.cors.allowed-origins:http://localhost:8110}") + private val allowedOrigins: String +) { + + @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) + fun swaggerCorsWebFilter(): CorsWebFilter { + val config = CorsConfiguration().apply { + allowedOrigins = if (enabled) { + this@OpenApiCorsConfig.allowedOrigins + .split(",") + .map { it.trim() } + .filter { it.isNotBlank() } + } else { + emptyList() + } + + allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS") + allowedHeaders = listOf("*") + exposedHeaders = listOf("Location", "Content-Disposition") + allowCredentials = false + maxAge = 3600 + } + + val source = UrlBasedCorsConfigurationSource() + source.registerCorsConfiguration("/**", config) + + return CorsWebFilter(source) + } +} \ No newline at end of file diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/SecurityConfig.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/SecurityConfig.kt index 5b2a71194..3911ec4ff 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/SecurityConfig.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/SecurityConfig.kt @@ -1,13 +1,13 @@ package co.nilin.opex.auth.config import co.nilin.opex.auth.utils.AudienceValidator -import jakarta.enterprise.inject.Default import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Primary import org.springframework.core.annotation.Order -import org.springframework.security.authorization.AuthorizationDecision +import org.springframework.http.HttpMethod import org.springframework.security.config.Customizer import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity import org.springframework.security.config.web.server.ServerHttpSecurity @@ -15,7 +15,6 @@ import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator import org.springframework.security.oauth2.jwt.JwtValidators import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder -import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken import org.springframework.security.web.server.SecurityWebFilterChain import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers import org.springframework.web.reactive.function.client.WebClient @@ -23,21 +22,36 @@ import org.springframework.web.reactive.function.client.WebClient @EnableWebFluxSecurity @Configuration class SecurityConfig( - @Qualifier("keycloakWebClient") - private val webClient: WebClient, - private val keycloakConfig: KeycloakConfig + @Qualifier("keycloakWebClient") private val webClient: WebClient, + private val keycloakConfig: KeycloakConfig, ) { + @Value("\${swagger.auth.enabled:false}") + private var swaggerAuthEnabled: Boolean = false + + @Value("\${swagger.auth.authority:ROLE_admin}") + private lateinit var swaggerAuthority: String + @Bean - @Order(2) - fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { - return http.csrf { it.disable() } - .authorizeExchange {it.pathMatchers("/actuator/**").permitAll() - .pathMatchers("/v1/oauth/protocol/openid-connect/**").permitAll() - .pathMatchers("/v1/oauth.***").permitAll() - .pathMatchers("/v1/user/public/**").permitAll() - .pathMatchers("/v1/user/update/**").permitAll() - .anyExchange().authenticated() + @Order(0) + fun swaggerSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + val swaggerPaths = arrayOf( + "/swagger-ui.html", + "/swagger-ui/**", + "/v3/api-docs", + "/v3/api-docs/**", + "/webjars/**" + ) + + return http + .securityMatcher(ServerWebExchangeMatchers.pathMatchers(*swaggerPaths)) + .csrf { it.disable() } + .authorizeExchange { + if (swaggerAuthEnabled) { + it.anyExchange().hasAuthority(swaggerAuthority) + } else { + it.anyExchange().permitAll() + } } .oauth2ResourceServer { it.jwt(Customizer.withDefaults()) } .build() @@ -52,19 +66,30 @@ class SecurityConfig( "/v1/oauth/protocol/openid-connect/token/resend-otp" ) ) + .csrf { it.disable() } + .authorizeExchange { it.anyExchange().authenticated() } + .oauth2ResourceServer { it.jwt { jwt -> jwt.jwtDecoder(preAuthJwtDecoder()) } } + .build() + } + + @Bean + @Order(2) + fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http .csrf { it.disable() } .authorizeExchange { - it.anyExchange().authenticated() - } - .oauth2ResourceServer { it -> - it.jwt { - it.jwtDecoder(preAuthJwtDecoder()) - } + it.pathMatchers("/actuator/**").permitAll() + .pathMatchers("/v1/oauth/protocol/openid-connect/**").permitAll() + .pathMatchers("/v1/oauth.***").permitAll() + .pathMatchers("/v1/user/public/**").permitAll() + .pathMatchers("/v1/user/update/**").permitAll() + .pathMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .anyExchange().authenticated() } + .oauth2ResourceServer { it.jwt(Customizer.withDefaults()) } .build() } - @Bean @Throws(Exception::class) @Primary @@ -90,7 +115,6 @@ class SecurityConfig( return decoder } - @Bean("preAuthJwtDecoder") @Throws(Exception::class) fun preAuthJwtDecoder(): ReactiveJwtDecoder? { @@ -112,5 +136,3 @@ class SecurityConfig( return decoder } } - - diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/AuthController.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/AuthController.kt index 04d5e12c3..5270d40d4 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/AuthController.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/AuthController.kt @@ -1,7 +1,20 @@ -package co.nilin.opex.auth.controller; +package co.nilin.opex.auth.controller -import co.nilin.opex.auth.model.* +import co.nilin.opex.auth.model.ConfirmPasswordFlowTokenRequest +import co.nilin.opex.auth.model.ExternalIdpTokenRequest +import co.nilin.opex.auth.model.PasswordFlowTokenRequest +import co.nilin.opex.auth.model.RefreshTokenRequest +import co.nilin.opex.auth.model.ResendOtpRequest +import co.nilin.opex.auth.model.ResendOtpResponse +import co.nilin.opex.auth.model.TokenResponse import co.nilin.opex.auth.service.LoginService +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext @@ -12,23 +25,76 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/v1/oauth/protocol/openid-connect/") +@Tag( + name = "Auth Gateway - Token", + description = "Token, OTP confirmation, external IdP token, and refresh-token operations." +) class AuthController(private val loginService: LoginService) { @PostMapping("/token") + @Operation( + summary = "Request token", + description = """POST /v1/oauth/protocol/openid-connect/token. +Security: Public endpoint. No Bearer token is required. + +Behavior: Starts password-flow login. If OTP is required, the response contains OTP metadata instead of a final access token. +Allowed values: +- captchaType: INTERNAL, ARCAPTCHA, HCAPTCHA.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = TokenResponse::class))] + ) + ] + ) suspend fun requestGetToken(@RequestBody tokenRequest: PasswordFlowTokenRequest): ResponseEntity { val tokenResponse = loginService.requestGetToken(tokenRequest) return ResponseEntity.ok().body(tokenResponse) } @PostMapping("/token/confirm") + @Operation( + summary = "Confirm token request", + description = """POST /v1/oauth/protocol/openid-connect/token/confirm. +Security: Public endpoint. No Bearer token is required. + +Validation: `otp` and the pre-auth `token` returned by the token request flow are required. +Behavior: Completes password-flow login after OTP verification.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = TokenResponse::class))] + ) + ] + ) suspend fun confirmGetToken(@RequestBody tokenRequest: ConfirmPasswordFlowTokenRequest): ResponseEntity { val tokenResponse = loginService.confirmGetToken(tokenRequest) return ResponseEntity.ok().body(tokenResponse) } @PostMapping("/token/resend-otp") + @Operation( + summary = "Resend login OTP", + description = """POST /v1/oauth/protocol/openid-connect/token/resend-otp. +Security: Bearer pre-auth token required. + +Behavior: Resends the OTP for an in-progress login flow. +Source of values: Use the pre-auth token returned by the token request flow.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = ResendOtpResponse::class))] + ), + ApiResponse(responseCode = "401", description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", content = [Content()]) + ] + ) suspend fun resendOtp( @RequestBody resendOtpRequest: ResendOtpRequest, + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, ): ResponseEntity { val response = loginService.resendLoginOtp(resendOtpRequest, securityContext.authentication.name) @@ -36,12 +102,41 @@ class AuthController(private val loginService: LoginService) { } @PostMapping("/token-external") + @Operation( + summary = "Request token by external IdP", + description = """POST /v1/oauth/protocol/openid-connect/token-external. +Security: Public endpoint. No Bearer token is required. + +Behavior: Exchanges an external identity-provider token for an Opex token. OTP verification data may be required depending on the account state.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = TokenResponse::class))] + ) + ] + ) suspend fun getToken(@RequestBody tokenRequest: ExternalIdpTokenRequest): ResponseEntity { val tokenResponse = loginService.getToken(tokenRequest) return ResponseEntity.ok().body(tokenResponse) } @PostMapping("/refresh") + @Operation( + summary = "Refresh token", + description = """POST /v1/oauth/protocol/openid-connect/refresh. +Security: Public endpoint. No Bearer token is required. + +Validation: `refreshToken` and `clientId` are required. +Behavior: Issues a new access token from a valid refresh token.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(implementation = TokenResponse::class))] + ) + ] + ) suspend fun refreshToken(@RequestBody tokenRequest: RefreshTokenRequest): ResponseEntity { val tokenResponse = loginService.refreshToken(tokenRequest) return ResponseEntity.ok().body(tokenResponse) diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/PublicUserController.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/PublicUserController.kt index c63d8dfde..7b48faeaa 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/PublicUserController.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/PublicUserController.kt @@ -3,6 +3,11 @@ package co.nilin.opex.auth.controller import co.nilin.opex.auth.model.* import co.nilin.opex.auth.service.ForgetPasswordService import co.nilin.opex.auth.service.RegisterService +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PostMapping @@ -12,53 +17,171 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/v1/user/public") +@Tag( + name = "Auth Gateway - Public User", + description = "Public registration and password-recovery operations." +) class PublicUserController( private val forgetPasswordService: ForgetPasswordService, private val registerService: RegisterService ) { - //TODO IMPORTANT: remove in production @PostMapping("/register") + @Operation( + summary = "Register user", + description = """POST /v1/user/public/register. +Security: Public endpoint. No Bearer token is required. + +Behavior: Starts the registration flow and sends OTP if required. +Allowed values: +- captchaType: INTERNAL, ARCAPTCHA, HCAPTCHA.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "object"))] + ) + ] + ) suspend fun registerUser(@Valid @RequestBody request: RegisterUserRequest): ResponseEntity { val otpResponse = registerService.registerUser(request) return ResponseEntity.ok().body(otpResponse) } @PostMapping("/register/verify") + @Operation( + summary = "Verify registration OTP", + description = """POST /v1/user/public/register/verify. +Security: Public endpoint. No Bearer token is required. + +Validation: `username` and `otp` are required. +Behavior: Returns an action token used to confirm registration.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = OTPActionTokenResponse::class) + )] + ) + ] + ) suspend fun verifyRegister(@RequestBody request: VerifyOTPRequest): ResponseEntity { val token = registerService.verifyRegister(request) return ResponseEntity.ok(OTPActionTokenResponse(token)) } @PostMapping("/register/confirm") + @Operation( + summary = "Confirm registration", + description = """POST /v1/user/public/register/confirm. +Security: Public endpoint. No Bearer token is required. + +Validation: `password` and registration action `token` are required. +Behavior: Completes registration and returns login token data.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = TokenResponse::class) + )] + ) + ] + ) suspend fun confirmRegister(@RequestBody request: ConfirmRegisterRequest): ResponseEntity { val loginToken = registerService.confirmRegister(request) return ResponseEntity.ok(loginToken) } @PostMapping("/register-external") + @Operation( + summary = "Register external IdP user", + description = """POST /v1/user/public/register-external. +Security: Public endpoint. No Bearer token is required. + +Behavior: Registers a user from an external identity provider token. +Response body: No response body.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ) + ] + ) suspend fun registerExternal(@RequestBody request: ExternalIdpUserRegisterRequest): ResponseEntity { registerService.registerExternalIdpUser(request) return ResponseEntity.ok().build() } - //TODO IMPORTANT: remove in production @PostMapping("/forget") + @Operation( + summary = "Forgot password", + description = """POST /v1/user/public/forget. +Security: Public endpoint. No Bearer token is required. + +Behavior: Starts password-recovery flow and sends OTP if required. +Allowed values: +- captchaType: INTERNAL, ARCAPTCHA, HCAPTCHA.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content(mediaType = "application/json", schema = Schema(type = "object"))] + ) + ] + ) suspend fun forgetPassword(@RequestBody request: ForgotPasswordRequest): ResponseEntity { val otpResponse = forgetPasswordService.forgetPassword(request) return ResponseEntity.ok().body(otpResponse) } @PostMapping("/forget/verify") + @Operation( + summary = "Verify forgot-password OTP", + description = """POST /v1/user/public/forget/verify. +Security: Public endpoint. No Bearer token is required. + +Validation: `username` and `otp` are required. +Behavior: Returns an action token used to confirm password reset.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = OTPActionTokenResponse::class) + )] + ) + ] + ) suspend fun verifyForget(@RequestBody request: VerifyOTPRequest): ResponseEntity { val token = forgetPasswordService.verifyForget(request) return ResponseEntity.ok(OTPActionTokenResponse(token)) } @PostMapping("/forget/confirm") + @Operation( + summary = "Confirm forgot-password flow", + description = """POST /v1/user/public/forget/confirm. +Security: Public endpoint. No Bearer token is required. + +Validation: `newPassword`, `newPasswordConfirmation`, and password-reset action `token` are required. +Response body: No response body.""", + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ) + ] + ) suspend fun forgetPassword(@RequestBody request: ConfirmForgetRequest): ResponseEntity { forgetPasswordService.confirmForget(request) return ResponseEntity.ok().build() } -} \ No newline at end of file +} diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/SessionController.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/SessionController.kt index 5fe06d1f3..b2235ace6 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/SessionController.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/controller/SessionController.kt @@ -7,12 +7,25 @@ import co.nilin.opex.auth.service.LogoutService import co.nilin.opex.auth.service.SessionService import co.nilin.opex.common.OpexError import co.nilin.opex.common.security.jwtAuthentication +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.enums.ParameterIn +import io.swagger.v3.oas.annotations.media.ArraySchema +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.security.core.annotation.CurrentSecurityContext import org.springframework.security.core.context.SecurityContext import org.springframework.web.bind.annotation.* @RestController @RequestMapping("/v1/user") +@Tag( + name = "Auth Gateway - Sessions", + description = "Authenticated user session and logout operations." +) class SessionController( private val forgetPasswordService: ForgetPasswordService, private val logoutService: LogoutService, @@ -20,7 +33,31 @@ class SessionController( ) { @PostMapping("/logout") - suspend fun logout(@CurrentSecurityContext securityContext: SecurityContext) { + @Operation( + summary = "Logout current session", + description = """POST /v1/user/logout. +Security: Bearer user-token required. + +Behavior: Terminates the current session using the `sid` claim from the JWT. +Response body: No response body.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) + suspend fun logout( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ) { val userId = securityContext.jwtAuthentication().name val sid = securityContext.jwtAuthentication().tokenAttributes["sid"] as String? ?: throw OpexError.InvalidToken.exception() @@ -28,7 +65,34 @@ class SessionController( } @PostMapping("/session") + @Operation( + summary = "List user sessions", + description = """POST /v1/user/session. +Security: Bearer user-token required. + +Behavior: Returns user sessions for the authenticated user. `uuid` in the request body is overwritten by the authenticated user id. +Allowed values: +- os: ANDROID, IOS, MOBILE_WEB, DESKTOP_WEB +- status: ACTIVE, EXPIRED, TERMINATED.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response.", + content = [Content( + mediaType = "application/json", + array = ArraySchema(schema = Schema(implementation = Sessions::class)) + )] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) suspend fun getSessions( + @Parameter(hidden = true) @CurrentSecurityContext securityContext: SecurityContext, @RequestBody sessionRequest: SessionRequest ): List { @@ -40,13 +104,70 @@ class SessionController( } @DeleteMapping("/session/{sessionId}") - suspend fun logout(@CurrentSecurityContext securityContext: SecurityContext, @PathVariable sessionId: String) { + @Operation( + summary = "Logout one session", + description = """DELETE /v1/user/session/{sessionId}. +Security: Bearer user-token required. + +Behavior: Terminates one user session by id. +Response body: No response body.""", + security = [SecurityRequirement(name = "bearerAuth")], + parameters = [ + Parameter( + name = "sessionId", + `in` = ParameterIn.PATH, + required = true, + description = "Session id to terminate." + ) + ], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) + suspend fun logout( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext, + @PathVariable sessionId: String + ) { val uuid = securityContext.authentication.name logoutService.logoutSession(uuid, sessionId) } @PostMapping("/session/delete-others") - suspend fun logoutOthers(@CurrentSecurityContext securityContext: SecurityContext) { + @Operation( + summary = "Logout other sessions", + description = """POST /v1/user/session/delete-others. +Security: Bearer user-token required. + +Behavior: Terminates all sessions except the current JWT session. +Response body: No response body.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) + suspend fun logoutOthers( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ) { val uuid = securityContext.authentication.name val sid = securityContext.jwtAuthentication().tokenAttributes["sid"] as String? ?: throw OpexError.InvalidToken.exception() @@ -54,10 +175,32 @@ class SessionController( } @PostMapping("/session/delete-all") - suspend fun logoutAll(@CurrentSecurityContext securityContext: SecurityContext) { + @Operation( + summary = "Logout all sessions", + description = """POST /v1/user/session/delete-all. +Security: Bearer user-token required. + +Behavior: Terminates all sessions for the authenticated user. +Response body: No response body.""", + security = [SecurityRequirement(name = "bearerAuth")], + responses = [ + ApiResponse( + responseCode = "200", + description = "Successful response. No response body.", + content = [Content()] + ), + ApiResponse( + responseCode = "401", + description = "Unauthorized. Bearer token is missing, invalid, or expired. No response body.", + content = [Content()] + ) + ] + ) + suspend fun logoutAll( + @Parameter(hidden = true) + @CurrentSecurityContext securityContext: SecurityContext + ) { val uuid = securityContext.authentication.name logoutService.logoutAll(uuid) } - } - diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/model/OTP.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/model/OTP.kt index 148d26993..3cf756c22 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/model/OTP.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/model/OTP.kt @@ -25,7 +25,6 @@ data class OTPVerifyResponse( val type: OTPResultType ) -//TODO IMPORTANT: remove in production data class TempOtpResponse(val otp: String?, val otpReceiver: OTPReceiver?) enum class OTPAction { diff --git a/auth-gateway/auth-gateway-app/src/main/resources/application.yml b/auth-gateway/auth-gateway-app/src/main/resources/application.yml index 5b1550467..68dd6b18e 100644 --- a/auth-gateway/auth-gateway-app/src/main/resources/application.yml +++ b/auth-gateway/auth-gateway-app/src/main/resources/application.yml @@ -80,12 +80,22 @@ app: custom-user-language: enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} pre-auth-client-secret: ${PRE_AUTH_CLIENT_SECRET} - + swagger: + cors: + enabled: true + allowed-origins: "http://localhost:8110" # --- Swagger / SpringDoc (env-driven) --- springdoc: api-docs: enabled: ${SWAGGER_API_DOCS_ENABLED:false} + path: ${SWAGGER_API_DOCS_PATH:/v3/api-docs} + swagger-ui: enabled: ${SWAGGER_UI_ENABLED:false} path: ${SWAGGER_UI_PATH:/swagger-ui.html} + try-it-out-enabled: ${SWAGGER_TRY_IT_OUT_ENABLED:true} + persist-authorization: ${SWAGGER_PERSIST_AUTHORIZATION:true} + display-request-duration: true + operations-sorter: method + tags-sorter: alpha diff --git a/docker-compose.yml b/docker-compose.yml index 1bfa5b004..ce88c3c44 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -422,6 +422,10 @@ services: - CUSTOM_MESSAGE_URL=${CUSTOM_MESSAGE_URL} - CUSTOM_MESSAGE_ENABLED=${CUSTOM_MESSAGE_ENABLED} - CUSTOM_USER_LANGUAGE_ENABLED=${CUSTOM_USER_LANGUAGE_ENABLED} + - SWAGGER_API_DOCS_ENABLED=${SWAGGER_API_DOCS_ENABLED} + - SWAGGER_UI_ENABLED=${SWAGGER_UI_ENABLED} + - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} + - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} volumes: - auth-gateway-keys:/app/keys depends_on: @@ -657,6 +661,33 @@ services: deploy: restart_policy: condition: on-failure + swagger-docs: + image: swaggerapi/swagger-ui:latest + profiles: + - docs + ports: + - "8110:8080" + environment: + URLS: > + [ + { + "name": "Opex API", + "url": "http://localhost:8094/v3/api-docs" + }, + { + "name": "Opex Auth Gateway", + "url": "http://localhost:8184/v3/api-docs" + } + ] + URLS_PRIMARY_NAME: "Opex API" + DOC_EXPANSION: "none" + DEFAULT_MODELS_EXPAND_DEPTH: "-1" + DISPLAY_REQUEST_DURATION: "true" + DEEP_LINKING: "true" + PERSIST_AUTHORIZATION: "true" + TRY_IT_OUT_ENABLED: "true" + FILTER: "true" + VALIDATOR_URL: "none" volumes: zookeeper-data: zookeeper-log: From 3dc9402f86bf46b2aa2df397a9b80f1ff2840d67 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Fri, 29 May 2026 19:05:05 +0330 Subject: [PATCH 52/56] Update the swagger doc service to be usable in all envs --- docker-compose.local.yml | 3 +++ docker-compose.yml | 16 ++-------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/docker-compose.local.yml b/docker-compose.local.yml index 556a9e475..3ab397629 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -86,4 +86,7 @@ services: ports: - "0.0.0.0:8099:8080" - "127.0.0.1:1057:5005" + swagger-docs: + ports: + - "0.0.0.0:8110:8080" diff --git a/docker-compose.yml b/docker-compose.yml index ce88c3c44..bb427887e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -665,21 +665,9 @@ services: image: swaggerapi/swagger-ui:latest profiles: - docs - ports: - - "8110:8080" environment: - URLS: > - [ - { - "name": "Opex API", - "url": "http://localhost:8094/v3/api-docs" - }, - { - "name": "Opex Auth Gateway", - "url": "http://localhost:8184/v3/api-docs" - } - ] - URLS_PRIMARY_NAME: "Opex API" + URLS: ${SWAGGER_DOCS_URLS} + URLS_PRIMARY_NAME: ${SWAGGER_DOCS_PRIMARY_NAME:-Opex API} DOC_EXPANSION: "none" DEFAULT_MODELS_EXPAND_DEPTH: "-1" DISPLAY_REQUEST_DURATION: "true" From a48289cdccf2f3892846487ced13c079ea41f7a3 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sat, 30 May 2026 12:52:22 +0330 Subject: [PATCH 53/56] Rm insomnia file --- Insomnia_2026-05-10.json | 1098 -------------------------------------- 1 file changed, 1098 deletions(-) delete mode 100644 Insomnia_2026-05-10.json diff --git a/Insomnia_2026-05-10.json b/Insomnia_2026-05-10.json deleted file mode 100644 index a83475896..000000000 --- a/Insomnia_2026-05-10.json +++ /dev/null @@ -1,1098 +0,0 @@ -{ - "_type": "export", - "__export_format": 4, - "__export_date": "2026-05-10T18:55:00Z", - "__export_source": "junie-discovery", - "resources": [ - { - "_id": "wrk_opex", - "_type": "workspace", - "parentId": null, - "name": "Opex API (Discovery)", - "description": "Discovery-only collection. Enum options and body specs are documented in each request description." - }, - { - "_id": "env_opex_root", - "_type": "environment", - "parentId": "wrk_opex", - "name": "Base Environment", - "data": { - "host": "http://localhost:8094", - "api-host": "http://localhost:8094", - "auth-host": "http://localhost:8083", - "wallet-host": "http://localhost:8091", - "admin-host": "http://localhost:8098", - "config-host": "http://localhost:9088", - "user-token": "", - "admin-token": "", - "client-token": "", - "id": "1", - "withdrawUuid": "00000000-0000-0000-0000-000000000000", - "otpType": "SMS", - "otpCode": "123456", - "currency": "USDT", - "terminalUuid": "terminal-uuid-sample", - "gatewayUuid": "ofg-uuid-sample", - "code": "VCHR-TEST", - "symbol": "BTCUSDT", - "interval": "Month", - "bucket": "public", - "key": "logo.png", - "sourceSymbol": "BTC", - "destSymbol": "USDT", - "unit": "USDT", - "transitiveSymbol": "USDT" - } - }, - { - "_id": "fld_api_opex_rest", - "_type": "request_group", - "parentId": "wrk_opex", - "name": "api-ports / api-opex-rest" - }, - { - "_id": "fld_addressbook", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Address Book" - }, - { - "_id": "req_addr_add", - "_type": "request", - "parentId": "fld_addressbook", - "name": "POST /opex/v1/address-book", - "method": "POST", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is a server-provided string value.\n- Clients should use the exact value returned by the related chain/address-type source service.\n- Do not treat addressType as a fixed enum and do not hardcode a static value list.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nResponse 401:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/address-book", - "body": { - "mimeType": "application/json", - "text": "{\n \"name\": \"Home Wallet\",\n \"address\": \"0x...\",\n \"addressType\": \"ethereum\"\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_addr_list", - "_type": "request", - "parentId": "fld_addressbook", - "name": "GET /opex/v1/address-book", - "method": "GET", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nResponse 200: Array\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n }\n]\n\nResponse 401:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/address-book", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_addr_delete", - "_type": "request", - "parentId": "fld_addressbook", - "name": "DELETE /opex/v1/address-book/{id}", - "method": "DELETE", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.\n\nResponse 401:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_addr_update", - "_type": "request", - "parentId": "fld_addressbook", - "name": "PUT /opex/v1/address-book/{id}", - "method": "PUT", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n- No dedicated address-book permission is required.\n\nPath params:\n- id: Long\n\nRequest body: AddAddressBookItemRequest\n{\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nNotes:\n- addressType is a server-provided string value.\n- Clients should use the exact value returned by the related chain/address-type source service.\n- Do not treat addressType as a fixed enum and do not hardcode a static value list.\n\nResponse 200: AddressBookResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string\",\n \"address\": \"string\",\n \"addressType\": \"string\"\n}\n\nResponse 401:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/address-book/{{ _['id'] }}", - "body": { - "mimeType": "application/json", - "text": "{\n \"name\": \"Updated Name\",\n \"address\": \"0x...\",\n \"addressType\": \"ethereum\"\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_storage_admin", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Storage Admin" - }, - { - "_id": "req_storage_get", - "_type": "request", - "parentId": "fld_storage_admin", - "name": "GET /opex/v1/admin/storage", - "method": "GET", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nBinary file stream.\nContent-Type: application/octet-stream\nSchema:\n{\n \"type\": \"string\",\n \"format\": \"binary\"\n}", - "url": "{{ _['api-host'] }}/opex/v1/admin/storage", - "parameters": [ - { - "name": "bucket", - "value": "{{ _['bucket'] }}", - "description": "Bucket name" - }, - { - "name": "key", - "value": "{{ _['key'] }}", - "description": "Object key" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_storage_post", - "_type": "request", - "parentId": "fld_storage_admin", - "name": "POST /opex/v1/admin/storage", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- bucket: string\n- key: string\n- isPublic: boolean | null, default false\n\nMultipart form-data parts:\n- file: binary file\n\nResponse 200: string\nExample:\n\"http://localhost:8094/opex/v1/storage?bucket=public&key=logo.png\"", - "url": "{{ _['api-host'] }}/opex/v1/admin/storage", - "parameters": [ - { - "name": "bucket", - "value": "{{ _['bucket'] }}", - "description": "Bucket name" - }, - { - "name": "key", - "value": "{{ _['key'] }}", - "description": "Object key" - }, - { - "name": "isPublic", - "value": "false", - "description": "Publicly accessible if true" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - }, - "body": { - "mimeType": "multipart/form-data", - "params": [ - { - "name": "file", - "type": "file", - "fileName": "/path/to/file.png" - } - ], - "paramsOrder": [ - "file" - ] - } - }, - { - "_id": "req_storage_delete", - "_type": "request", - "parentId": "fld_storage_admin", - "name": "DELETE /opex/v1/admin/storage", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- bucket: string\n- key: string\n\nResponse 200:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/admin/storage", - "parameters": [ - { - "name": "bucket", - "value": "{{ _['bucket'] }}", - "description": "Bucket name" - }, - { - "name": "key", - "value": "{{ _['key'] }}", - "description": "Object key" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_withdraw", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Withdraw" - }, - { - "_id": "req_withdraw_post", - "_type": "request", - "parentId": "fld_withdraw", - "name": "POST /opex/v1/withdraw", - "method": "POST", - "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_withdraw:write.\n\nRequest body: RequestWithdrawBody\n{\n \"currency\": \"string\",\n \"amount\": \"BigDecimal\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"gatewayUuid\": \"string | null\"\n}\n\nResponse 200: WithdrawActionResult | null\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", - "url": "{{ _['api-host'] }}/opex/v1/withdraw", - "body": { - "mimeType": "application/json", - "text": "{\n \"currency\": \"USDT\",\n \"amount\": 50.00,\n \"destSymbol\": null,\n \"destAddress\": \"0x...\",\n \"destNetwork\": null,\n \"destNote\": null,\n \"gatewayUuid\": null\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_withdraw_cancel", - "_type": "request", - "parentId": "fld_withdraw", - "name": "PUT /opex/v1/withdraw/{withdrawUuid}/cancel", - "method": "PUT", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n\nResponse 200:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/cancel", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_withdraw_find", - "_type": "request", - "parentId": "fld_withdraw", - "name": "GET /opex/v1/withdraw/{withdrawUuid}", - "method": "GET", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n\nResponse 200: WithdrawResponse\n{\n \"withdrawId\": \"string\",\n \"uuid\": \"string\",\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"appliedFee\": \"BigDecimal\",\n \"destAmount\": \"BigDecimal | null\",\n \"destSymbol\": \"string | null\",\n \"destAddress\": \"string | null\",\n \"destNetwork\": \"string | null\",\n \"destNote\": \"string | null\",\n \"destTransactionRef\": \"string | null\",\n \"statusReason\": \"string | null\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"applicator\": \"string | null\",\n \"withdrawType\": \"CARD_TO_CARD | SHEBA | ON_CHAIN | OFF_CHAIN\",\n \"attachment\": \"string | null\",\n \"createDate\": \"LocalDateTime\",\n \"lastUpdateDate\": \"LocalDateTime | null\",\n \"transferMethod\": \"CARD | SHEBA | IPG | EXCHANGE | MANUALLY | VOUCHER | MPG | REWARD | null\",\n \"otpRequired\": \"integer | null\"\n}", - "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_withdraw_otp_req", - "_type": "request", - "parentId": "fld_withdraw", - "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/request", - "method": "POST", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nResponse 200: TempOtpResponse\n{\n \"otp\": \"string | null\",\n \"receivers\": [\n {\n \"receiver\": \"string\",\n \"type\": \"SMS | EMAIL\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/request", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_withdraw_otp_verify", - "_type": "request", - "parentId": "fld_withdraw", - "name": "POST /opex/v1/withdraw/{withdrawUuid}/otp/{otpType}/verify", - "method": "POST", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nPath params:\n- withdrawUuid: string\n- otpType: SMS | EMAIL\n\nQuery params:\n- otpCode: string\n\nResponse 200: WithdrawActionResult\n{\n \"withdrawId\": \"string\",\n \"status\": \"REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\",\n \"nextAction\": \"OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null\"\n}\n\nEnums:\n- status: REQUESTED | CREATED | ACCEPTED | CANCELED | REJECTED | DONE\n- nextAction: OTP_EMAIL | OTP_MOBILE | WAITING_FOR_ADMIN | null", - "url": "{{ _['api-host'] }}/opex/v1/withdraw/{{ _['withdrawUuid'] }}/otp/{{ _['otpType'] }}/verify", - "parameters": [ - { - "name": "otpCode", - "value": "{{ _['otpCode'] }}", - "description": "OTP code" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_deposit", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Deposit" - }, - { - "_id": "req_deposit_post", - "_type": "request", - "parentId": "fld_deposit", - "name": "POST /opex/v1/deposit", - "method": "POST", - "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_deposit:write.\n\nRequest body: RequestDepositBody\n{\n \"symbol\": \"string\",\n \"receiverUuid\": \"string\",\n \"receiverWalletType\": \"WalletType\",\n \"amount\": \"BigDecimal\",\n \"description\": \"string | null\",\n \"transferRef\": \"string | null\",\n \"gatewayUuid\": \"string | null\",\n \"chain\": \"string | null\"\n}\n\nNotes:\n- receiverWalletType uses WalletType. The current request DTO references WalletType, but this collection does not lock specific enum values.\n\nResponse 200: TransferResult | null\n{\n \"date\": \"Long\",\n \"sourceUuid\": \"string\",\n \"sourceWalletType\": \"WalletType\",\n \"sourceBalanceBeforeAction\": {\n \"currency\": {\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n },\n \"amount\": \"BigDecimal\"\n },\n \"sourceBalanceAfterAction\": Amount,\n \"amount\": Amount,\n \"destUuid\": \"string\",\n \"destWalletType\": \"WalletType\",\n \"receivedAmount\": Amount,\n \"sourceWallet\": \"Long | null\",\n \"destWallet\": \"Long | null\"\n}\n\nNested Amount:\n{\n \"currency\": CurrencyCommand,\n \"amount\": \"BigDecimal\"\n}\n\nNested CurrencyCommand:\n{\n \"symbol\": \"string\",\n \"uuid\": \"string | null\",\n \"name\": \"string | null\",\n \"precision\": \"BigDecimal\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"icon\": \"string | null\",\n \"isTransitive\": \"boolean | null\",\n \"isActive\": \"boolean | null\",\n \"sign\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"withdrawAllowed\": \"boolean | null\",\n \"depositAllowed\": \"boolean | null\",\n \"externalUrl\": \"string | null\",\n \"gateways\": \"array | null\",\n \"availableGatewayType\": \"string | null\",\n \"displayOrder\": \"integer | null\"\n}", - "url": "{{ _['api-host'] }}/opex/v1/deposit", - "body": { - "mimeType": "application/json", - "text": "{\n \"symbol\": \"USDT\",\n \"receiverUuid\": \"{{ _['id'] }}\",\n \"receiverWalletType\": \"MAIN\",\n \"amount\": 100.00,\n \"description\": null,\n \"transferRef\": null,\n \"gatewayUuid\": null,\n \"chain\": null\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_wallet_admin", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Wallet Admin" - }, - { - "_id": "req_wallet_admin_users", - "_type": "request", - "parentId": "fld_wallet_admin", - "name": "GET /opex/v1/admin/wallet/users", - "method": "GET", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nQuery params:\n- uuid: string | null\n- currency: string | null\n- excludeSystem: boolean, default false\n- limit: integer | null, default 10\n- offset: integer | null, default 0\n\nResponse 200: List\n[\n {\n \"uuid\": \"string\",\n \"title\": \"string\",\n \"wallets\": [\n {\n \"currency\": \"string\",\n \"free\": \"double\",\n \"locked\": \"double\",\n \"pendingWithdraw\": \"double\"\n }\n ]\n }\n]", - "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users", - "parameters": [ - { - "name": "excludeSystem", - "value": "false", - "description": "Exclude system wallets" - }, - { - "name": "limit", - "value": "10", - "description": "Page size" - }, - { - "name": "offset", - "value": "0", - "description": "Page offset" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_wallet_admin_system_total", - "_type": "request", - "parentId": "fld_wallet_admin", - "name": "GET /opex/v1/admin/wallet/system/total", - "method": "GET", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nResponse 200: List\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", - "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/system/total", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_wallet_admin_users_total", - "_type": "request", - "parentId": "fld_wallet_admin", - "name": "GET /opex/v1/admin/wallet/users/total", - "method": "GET", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nResponse 200: List | null\n[\n {\n \"currency\": \"string\",\n \"balance\": \"double\"\n }\n]", - "url": "{{ _['api-host'] }}/opex/v1/admin/wallet/users/total", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_voucher", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Voucher" - }, - { - "_id": "req_voucher_put", - "_type": "request", - "parentId": "fld_voucher", - "name": "PUT /opex/v1/voucher/{code}", - "method": "PUT", - "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_voucher:submit.\n\nPath params:\n- code: string\n\nResponse 200: SubmitVoucherResponse\n{\n \"amount\": \"BigDecimal\",\n \"currency\": \"string\",\n \"issuer\": \"string | null\",\n \"description\": \"string | null\"\n}", - "url": "{{ _['api-host'] }}/opex/v1/voucher/{{ _['code'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_user_data", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "User Data" - }, - { - "_id": "req_user_data_trade_volume", - "_type": "request", - "parentId": "fld_user_data", - "name": "GET /opex/v1/user/data/trade/volume", - "method": "GET", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nQuery params:\n- symbol: string, e.g. BTCUSDT\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", - "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume", - "parameters": [ - { - "name": "symbol", - "value": "{{ _['symbol'] }}", - "description": "Symbol, e.g., BTCUSDT" - }, - { - "name": "interval", - "value": "{{ _['interval'] }}", - "description": "Interval: Day | Week | Month | Year" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_user_data_trade_volume_total", - "_type": "request", - "parentId": "fld_user_data", - "name": "GET /opex/v1/user/data/trade/volume/total", - "method": "GET", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nQuery params:\n- interval: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", - "url": "{{ _['api-host'] }}/opex/v1/user/data/trade/volume/total", - "parameters": [ - { - "name": "interval", - "value": "{{ _['interval'] }}", - "description": "Interval: Day | Week | Month | Year" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_user_data_fee", - "_type": "request", - "parentId": "fld_user_data", - "name": "GET /opex/v1/user/data/fee", - "method": "GET", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nResponse 200: UserFee\n{\n \"name\": \"string\",\n \"makerFee\": \"BigDecimal\",\n \"takerFee\": \"BigDecimal\"\n}", - "url": "{{ _['api-host'] }}/opex/v1/user/data/fee", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_user_data_withdraw_total", - "_type": "request", - "parentId": "fld_user_data", - "name": "GET /opex/v1/user/data/withdraw/volume/total", - "method": "GET", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nQuery params:\n- interval: string | null\n- Accepted labels map to Interval, commonly: Day | Week | Month | Year\n\nResponse 200: BigDecimal\nExample:\n12345.6789", - "url": "{{ _['api-host'] }}/opex/v1/user/data/withdraw/volume/total", - "parameters": [ - { - "name": "interval", - "value": "{{ _['interval'] }}", - "description": "Optional label: Day | Week | Month | Year" - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_bank_account", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Bank Account" - }, - { - "_id": "req_bank_add", - "_type": "request", - "parentId": "fld_bank_account", - "name": "POST /opex/v1/bank-account", - "method": "POST", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nValidation:\n- Exactly one of `cardNumber` or `iban` must be provided.\n- Providing both or neither is invalid.\n\nRequest body: AddBankAccountRequest\n{\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\"\n}\n\nValid request with card number:\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": \"6037991234567890\",\n \"iban\": null\n}\n\nValid request with IBAN:\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": null,\n \"iban\": \"IR123456789012345678901234\"\n}\n\nInvalid request: both cardNumber and iban are provided.\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": \"6037991234567890\",\n \"iban\": \"IR123456789012345678901234\"\n}\n\nInvalid request: neither cardNumber nor iban is provided.\n{\n \"name\": \"My Bank Account\",\n \"cardNumber\": null,\n \"iban\": null\n}\n\nResponse 200: BankAccountResponse\n{\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n}\n\nResponse 401:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/bank-account", - "body": { - "mimeType": "application/json", - "text": "{\n \"name\": \"My Bank\",\n \"cardNumber\": null,\n \"iban\": \"IRxxxxxxxxxxxx\"\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_bank_list", - "_type": "request", - "parentId": "fld_bank_account", - "name": "GET /opex/v1/bank-account", - "method": "GET", - "description": "Auth:\n- Bearer user-token is required.\n- Requires a valid authenticated user JWT.\n\nResponse 200: Array\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"cardNumber\": \"string | null\",\n \"iban\": \"string | null\",\n \"accountNumber\": \"string | null\",\n \"bank\": \"string | null\",\n \"status\": \"WAITING | VERIFIED | REJECTED\"\n }\n]\n\nResponse 401:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/bank-account", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "req_bank_delete", - "_type": "request", - "parentId": "fld_bank_account", - "name": "DELETE /opex/v1/bank-account/{id}", - "method": "DELETE", - "description": "Auth:\n- Bearer user-token is required.\n- Required authority: PERM_bank_account:write.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.\n\nResponse 401:\nNo response body.\n\nResponse 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/bank-account/{{ _['id'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['user-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_localization_admin", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "Localization Admin" - }, - { - "_id": "req_loc_currency_get", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "GET /opex/v1/admin/currency/{currency}/localization", - "method": "GET", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- currency: string\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_currency_post", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "POST /opex/v1/admin/currency/{currency}/localization", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- currency: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: CurrencyLocalizationResponse\n{\n \"currency\": \"string\",\n \"currencyLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"name\": \"string | null\",\n \"title\": \"string | null\",\n \"alias\": \"string | null\",\n \"description\": \"string | null\",\n \"shortDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/admin/currency/{{ _['currency'] }}/localization", - "body": { - "mimeType": "application/json", - "text": "[\n {\n \"id\": null,\n \"name\": \"USDT\",\n \"title\": \"Tether USD\",\n \"alias\": \"Tether\",\n \"description\": \"Stablecoin description\",\n \"shortDescription\": \"Stablecoin\",\n \"language\": \"en\"\n }\n]" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_currency_delete", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "DELETE /opex/v1/admin/currency/localization/{id}", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/admin/currency/localization/{{ _['id'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_terminal_get", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "GET /opex/v1/admin/terminal/{terminalUuid}/localization", - "method": "GET", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- terminalUuid: string\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_terminal_post", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "POST /opex/v1/admin/terminal/{terminalUuid}/localization", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- terminalUuid: string\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: TerminalLocalizationResponse\n{\n \"terminalUuid\": \"string\",\n \"terminalLocalizations\": [\n {\n \"id\": \"Long | null\",\n \"description\": \"string | null\",\n \"owner\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/{{ _['terminalUuid'] }}/localization", - "body": { - "mimeType": "application/json", - "text": "[\n {\n \"id\": null,\n \"description\": \"Terminal description\",\n \"owner\": \"OPEX\",\n \"language\": \"en\"\n }\n]" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_terminal_delete", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "DELETE /opex/v1/admin/terminal/localization/{id}", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- id: Long\n\nResponse 200:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/admin/terminal/localization/{{ _['id'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_gateway_get", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "GET /opex/v1/admin/gateway/{gatewayUuid}/localization", - "method": "GET", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" uses off-chain gateway localization.\n- gatewayUuid starting with \"ong\" uses on-chain gateway localization.\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_gateway_post", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "POST /opex/v1/admin/gateway/{gatewayUuid}/localization", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- gatewayUuid: string\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" saves off-chain gateway localization.\n- gatewayUuid starting with \"ong\" saves on-chain gateway localization.\n\nRequest body: List\n[\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n]\n\nResponse 200: GatewayLocalizationResponse\n{\n \"gatewayUuid\": \"string\",\n \"localizations\": [\n {\n \"id\": \"Long | null\",\n \"depositDescription\": \"string | null\",\n \"withdrawDescription\": \"string | null\",\n \"language\": \"string\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization", - "body": { - "mimeType": "application/json", - "text": "[\n {\n \"id\": null,\n \"depositDescription\": \"Deposit via this gateway\",\n \"withdrawDescription\": \"Withdraw via this gateway\",\n \"language\": \"en\"\n }\n]" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_loc_gateway_delete", - "_type": "request", - "parentId": "fld_localization_admin", - "name": "DELETE /opex/v1/admin/gateway/{gatewayUuid}/localization/{id}", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required authority: ROLE_admin.\n\nPath params:\n- gatewayUuid: string\n- id: Long\n\nRouting rule:\n- gatewayUuid starting with \"ofg\" deletes off-chain gateway localization.\n- gatewayUuid starting with \"ong\" deletes on-chain gateway localization.\n\nResponse 200:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/admin/gateway/{{ _['gatewayUuid'] }}/localization/{{ _['id'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "fld_otc_rates", - "_type": "request_group", - "parentId": "fld_api_opex_rest", - "name": "OTC / Rates" - }, - { - "_id": "req_otc_rate_post", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "POST /opex/v1/otc/rate", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nValidation:\n- `rate` must be greater than zero.\n- `sourceSymbol` and `destSymbol` must be different.\n\nRequest body: SetCurrencyExchangeRateRequest\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"ignoreIfExist\": \"boolean | null\"\n}\n\nResponse 200:\nNo response body.\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/rate", - "body": { - "mimeType": "application/json", - "text": "{\n \"sourceSymbol\": \"BTC\",\n \"destSymbol\": \"USDT\",\n \"rate\": 65000.00,\n \"ignoreIfExist\": false\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_rate_put", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "PUT /opex/v1/otc/rate", - "method": "PUT", - "description": "Auth:\n- Bearer admin-token or service token is required.\n- Required role: ROLE_admin or ROLE_rate_bot.\n\nValidation:\n- `rate` must be greater than zero.\n- `sourceSymbol` and `destSymbol` must be different.\n\nRequest body: SetCurrencyExchangeRateRequest\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"ignoreIfExist\": \"boolean | null\"\n}\n\nResponse 200: Rates\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/rate", - "body": { - "mimeType": "application/json", - "text": "{\n \"sourceSymbol\": \"BTC\",\n \"destSymbol\": \"USDT\",\n \"rate\": 65100.00,\n \"ignoreIfExist\": false\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_rate_delete", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "DELETE /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nPath params:\n- sourceSymbol: string\n- destSymbol: string\n\nResponse 200: Rates\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/rate/{{ _['sourceSymbol'] }}/{{ _['destSymbol'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_rates_get", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "GET /opex/v1/otc/rate", - "method": "GET", - "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nResponse 200: Rates\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/otc/rate", - "headers": [] - }, - { - "_id": "req_otc_rate_get", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "GET /opex/v1/otc/rate/{sourceSymbol}/{destSymbol}", - "method": "GET", - "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nPath params:\n- sourceSymbol: string\n- destSymbol: string\n\nResponse 200: Rate, nullable\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\"\n}", - "url": "{{ _['api-host'] }}/opex/v1/otc/rate/{{ _['sourceSymbol'] }}/{{ _['destSymbol'] }}", - "headers": [] - }, - { - "_id": "req_otc_forbidden_post", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "POST /opex/v1/otc/forbidden-pairs", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nValidation:\n- `sourceSymbol` and `destSymbol` must be different.\n\nRequest body: CurrencyPair\n{\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\"\n}\n\nResponse 200:\nNo response body.\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/forbidden-pairs", - "body": { - "mimeType": "application/json", - "text": "{\n \"sourceSymbol\": \"BTC\",\n \"destSymbol\": \"IRR\"\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_forbidden_delete", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "DELETE /opex/v1/otc/forbidden-pairs/{sourceSymbol}/{destSymbol}", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nPath params:\n- sourceSymbol: string\n- destSymbol: string\n\nResponse 200: ForbiddenPairs\n{\n \"forbiddenPairs\": [\n {\n \"sourceSymbol\": \"string\",\n \"destinationSymbol\": \"string\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/forbidden-pairs/{{ _['sourceSymbol'] }}/{{ _['destSymbol'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_forbidden_get", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "GET /opex/v1/otc/forbidden-pairs", - "method": "GET", - "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nResponse 200: ForbiddenPairs\n{\n \"forbiddenPairs\": [\n {\n \"sourceSymbol\": \"string\",\n \"destinationSymbol\": \"string\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/otc/forbidden-pairs", - "headers": [] - }, - { - "_id": "req_otc_transitive_post", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "POST /opex/v1/otc/transitive-symbols", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nRequest body: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 200:\nNo response body.\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols", - "body": { - "mimeType": "application/json", - "text": "{\n \"symbols\": [\n \"USDT\",\n \"IRR\"\n ]\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_transitive_delete_one", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "DELETE /opex/v1/otc/transitive-symbols/{symbol}", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nPath params:\n- symbol: string\n\nResponse 200: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols/{{ _['transitiveSymbol'] }}", - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_transitive_delete_bulk", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "DELETE /opex/v1/otc/transitive-symbols", - "method": "DELETE", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nRequest body: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 200: Symbols\n{\n \"symbols\": [\"string\"]\n}\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols", - "body": { - "mimeType": "application/json", - "text": "{\n \"symbols\": [\n \"USDT\",\n \"IRR\"\n ]\n}" - }, - "headers": [ - { - "name": "Content-Type", - "value": "application/json" - } - ], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_transitive_get", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "GET /opex/v1/otc/transitive-symbols", - "method": "GET", - "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nResponse 200: Symbols\n{\n \"symbols\": [\"string\"]\n}", - "url": "{{ _['api-host'] }}/opex/v1/otc/transitive-symbols", - "headers": [] - }, - { - "_id": "req_otc_route_get", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "GET /opex/v1/otc/route", - "method": "GET", - "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nQuery params:\n- sourceSymbol: string, optional. If omitted, all possible source symbols are considered.\n- destSymbol: string, optional. If omitted, all possible destination symbols are considered.\n\nRoute calculation behavior:\n- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair.\n- If sourceSymbol is omitted, routes are calculated from all possible source symbols.\n- If destSymbol is omitted, routes are calculated to all possible destination symbols.\n- If both are omitted, routes are calculated for all possible symbol combinations.\n- Do not send the literal string \"null\". Remove/disable the query parameter when it should be treated as null.\n\nUsage examples:\n- Specific pair: keep both sourceSymbol and destSymbol.\n- All destinations from one source: keep sourceSymbol and remove/disable destSymbol.\n- All sources to one destination: keep destSymbol and remove/disable sourceSymbol.\n- All possible combinations: remove/disable both sourceSymbol and destSymbol.\n\nResponse 200: CurrencyExchangeRatesResponse\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"isSwappable\": \"boolean\"\n }\n ]\n}", - "url": "{{ _['api-host'] }}/opex/v1/otc/route", - "parameters": [ - { - "name": "sourceSymbol", - "value": "{{ _['sourceSymbol'] }}", - "description": "Optional source currency symbol. If omitted, all possible source symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." - }, - { - "name": "destSymbol", - "value": "{{ _['destSymbol'] }}", - "description": "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." - } - ], - "headers": [] - }, - { - "_id": "req_otc_route_post", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "POST /opex/v1/otc/route", - "method": "POST", - "description": "Auth:\n- Bearer admin-token is required.\n- Required role: ROLE_admin.\n\nQuery params:\n- sourceSymbol: string, optional. If omitted, all possible source symbols are considered.\n- destSymbol: string, optional. If omitted, all possible destination symbols are considered.\n\nRoute calculation behavior:\n- If both sourceSymbol and destSymbol are provided, routes are calculated for that specific pair.\n- If sourceSymbol is omitted, routes are calculated from all possible source symbols.\n- If destSymbol is omitted, routes are calculated to all possible destination symbols.\n- If both are omitted, routes are calculated for all possible symbol combinations.\n- Do not send the literal string \"null\". Remove/disable the query parameter when it should be treated as null.\n\nUsage examples:\n- Specific pair: keep both sourceSymbol and destSymbol.\n- All destinations from one source: keep sourceSymbol and remove/disable destSymbol.\n- All sources to one destination: keep destSymbol and remove/disable sourceSymbol.\n- All possible combinations: remove/disable both sourceSymbol and destSymbol.\n\nRequest body:\nNo request body.\n\nResponse 200: CurrencyExchangeRatesResponse\n{\n \"rates\": [\n {\n \"sourceSymbol\": \"string\",\n \"destSymbol\": \"string\",\n \"rate\": \"BigDecimal\",\n \"isSwappable\": \"boolean\"\n }\n ]\n}\n\nResponse 401 / 403:\nNo response body.", - "url": "{{ _['api-host'] }}/opex/v1/otc/route", - "parameters": [ - { - "name": "sourceSymbol", - "value": "{{ _['sourceSymbol'] }}", - "description": "Optional source currency symbol. If omitted, all possible source symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." - }, - { - "name": "destSymbol", - "value": "{{ _['destSymbol'] }}", - "description": "Optional destination currency symbol. If omitted, all possible destination symbols are considered. Remove/disable this parameter instead of sending the literal string \"null\"." - } - ], - "headers": [], - "authentication": { - "type": "bearer", - "disabled": false, - "token": "{{_['admin-token']}}", - "prefix": "" - } - }, - { - "_id": "req_otc_currency_price_get", - "_type": "request", - "parentId": "fld_otc_rates", - "name": "GET /opex/v1/otc/currency/price", - "method": "GET", - "description": "Auth:\n- Public endpoint. No Bearer token is required.\n\nQuery params:\n- unit: string, required\n\nResponse 200: Array\n[\n {\n \"currency\": \"string\",\n \"buyPrice\": \"BigDecimal | null\",\n \"sellPrice\": \"BigDecimal | null\"\n }\n]", - "url": "{{ _['api-host'] }}/opex/v1/otc/currency/price", - "parameters": [ - { - "name": "unit", - "value": "{{ _['unit'] }}", - "description": "Pricing unit" - } - ], - "headers": [] - } - ] -} \ No newline at end of file From 26244ffac3499a83732a87b9a0bb540dd9b69332 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sat, 30 May 2026 16:16:14 +0330 Subject: [PATCH 54/56] Handle allowed origins dynamically --- .../app/config/{OpenApiCorsConfig.kt => CorsConfig.kt} | 8 ++++---- api/api-app/src/main/resources/application.yml | 7 +++---- .../config/{OpenApiCorsConfig.kt => CorsConfig.kt} | 10 +++++----- .../src/main/resources/application.yml | 7 +++---- docker-compose.yml | 4 ++-- 5 files changed, 17 insertions(+), 19 deletions(-) rename api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/{OpenApiCorsConfig.kt => CorsConfig.kt} (87%) rename auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/{OpenApiCorsConfig.kt => CorsConfig.kt} (84%) diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiCorsConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt similarity index 87% rename from api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiCorsConfig.kt rename to api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt index 02150efcf..d7f08bb75 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiCorsConfig.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt @@ -10,11 +10,11 @@ import org.springframework.web.cors.reactive.CorsWebFilter import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource @Configuration(proxyBeanMethods = false) -class OpenApiCorsConfig( - @Value("\${app.swagger.cors.enabled:false}") +class CorsConfig( + @Value("\${app.cors.enabled:false}") private val enabled: Boolean, - @Value("\${app.swagger.cors.allowed-origins:http://localhost:8110}") + @Value("\${app.cors.allowed-origins:http://localhost:8110}") private val allowedOrigins: String ) { @@ -23,7 +23,7 @@ class OpenApiCorsConfig( fun swaggerCorsWebFilter(): CorsWebFilter { val config = CorsConfiguration().apply { allowedOrigins = if (enabled) { - this@OpenApiCorsConfig.allowedOrigins + this@CorsConfig.allowedOrigins .split(",") .map { it.trim() } .filter { it.isNotBlank() } diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 353f13cc1..29bd59f40 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -149,10 +149,9 @@ app: api: crypto: key: ${api_crypto_key:0e1fd29572ec8c85970d76e3433e96ee} - swagger: - cors: - enabled: true - allowed-origins: "http://localhost:8110" + cors: + enabled: true + allowed-origins: ${ALLOWED_ORIGINS:"http://localhost:8110"} # --- Swagger / SpringDoc (env-driven) --- springdoc: diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiCorsConfig.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/CorsConfig.kt similarity index 84% rename from auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiCorsConfig.kt rename to auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/CorsConfig.kt index 5c31a0c2c..15a7bec43 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiCorsConfig.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/CorsConfig.kt @@ -10,20 +10,20 @@ import org.springframework.web.cors.reactive.CorsWebFilter import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource @Configuration(proxyBeanMethods = false) -class OpenApiCorsConfig( - @Value("\${app.swagger.cors.enabled:false}") +class CorsConfig( + @Value("\${app.cors.enabled:false}") private val enabled: Boolean, - @Value("\${app.swagger.cors.allowed-origins:http://localhost:8110}") + @Value("\${app.cors.allowed-origins:http://localhost:8110}") private val allowedOrigins: String ) { @Bean @Order(Ordered.HIGHEST_PRECEDENCE) - fun swaggerCorsWebFilter(): CorsWebFilter { + fun CorsWebFilter(): CorsWebFilter { val config = CorsConfiguration().apply { allowedOrigins = if (enabled) { - this@OpenApiCorsConfig.allowedOrigins + this@CorsConfig.allowedOrigins .split(",") .map { it.trim() } .filter { it.isNotBlank() } diff --git a/auth-gateway/auth-gateway-app/src/main/resources/application.yml b/auth-gateway/auth-gateway-app/src/main/resources/application.yml index 68dd6b18e..e114a9a6f 100644 --- a/auth-gateway/auth-gateway-app/src/main/resources/application.yml +++ b/auth-gateway/auth-gateway-app/src/main/resources/application.yml @@ -80,10 +80,9 @@ app: custom-user-language: enabled: ${CUSTOM_USER_LANGUAGE_ENABLED:false} pre-auth-client-secret: ${PRE_AUTH_CLIENT_SECRET} - swagger: - cors: - enabled: true - allowed-origins: "http://localhost:8110" + cors: + enabled: true + allowed-origins: ${ALLOWED_ORIGINS:"http://localhost:8110"} # --- Swagger / SpringDoc (env-driven) --- springdoc: diff --git a/docker-compose.yml b/docker-compose.yml index bb427887e..c8b020b6c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -426,6 +426,7 @@ services: - SWAGGER_UI_ENABLED=${SWAGGER_UI_ENABLED} - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} + - ALLOWED_ORIGINS:${ALLOWED_ORIGINS} volumes: - auth-gateway-keys:/app/keys depends_on: @@ -525,6 +526,7 @@ services: - SWAGGER_UI_ENABLED=${SWAGGER_UI_ENABLED} - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} + - ALLOWED_ORIGINS:${ALLOWED_ORIGINS} depends_on: - consul - vault @@ -663,8 +665,6 @@ services: condition: on-failure swagger-docs: image: swaggerapi/swagger-ui:latest - profiles: - - docs environment: URLS: ${SWAGGER_DOCS_URLS} URLS_PRIMARY_NAME: ${SWAGGER_DOCS_PRIMARY_NAME:-Opex API} From 62dc33a1670bf60d0a5cbfa5c19735cf2464c915 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sat, 30 May 2026 20:58:51 +0330 Subject: [PATCH 55/56] Log allowed origins in cors config --- .../co/nilin/opex/api/app/config/CorsConfig.kt | 13 ++++++++++--- api/api-app/src/main/resources/application.yml | 2 +- docker-compose.yml | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt index d7f08bb75..3176c59d6 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt @@ -1,5 +1,7 @@ package co.nilin.opex.api.app.config +import co.nilin.opex.common.utils.LoggerDelegate +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -14,13 +16,16 @@ class CorsConfig( @Value("\${app.cors.enabled:false}") private val enabled: Boolean, - @Value("\${app.cors.allowed-origins:http://localhost:8110}") + @Value("\${app.cors.allowed-origins}") private val allowedOrigins: String ) { + private val logger = LoggerFactory.getLogger(CorsConfig::class.java) + + @Bean @Order(Ordered.HIGHEST_PRECEDENCE) - fun swaggerCorsWebFilter(): CorsWebFilter { + fun corsWebFilter(): CorsWebFilter { val config = CorsConfiguration().apply { allowedOrigins = if (enabled) { this@CorsConfig.allowedOrigins @@ -30,7 +35,9 @@ class CorsConfig( } else { emptyList() } - + allowedOrigins?.forEach { + logger.info("Allowed origin: {}", it) + } allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS") allowedHeaders = listOf("*") exposedHeaders = listOf("Location", "Content-Disposition") diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 29bd59f40..0f617b009 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -151,7 +151,7 @@ app: key: ${api_crypto_key:0e1fd29572ec8c85970d76e3433e96ee} cors: enabled: true - allowed-origins: ${ALLOWED_ORIGINS:"http://localhost:8110"} + allowed-origins: ${ALLOWED_ORIGINS} # --- Swagger / SpringDoc (env-driven) --- springdoc: diff --git a/docker-compose.yml b/docker-compose.yml index c8b020b6c..fe8b874f2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -426,7 +426,7 @@ services: - SWAGGER_UI_ENABLED=${SWAGGER_UI_ENABLED} - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} - - ALLOWED_ORIGINS:${ALLOWED_ORIGINS} + - ALLOWED_ORIGINS=${ALLOWED_ORIGINS} volumes: - auth-gateway-keys:/app/keys depends_on: @@ -526,7 +526,7 @@ services: - SWAGGER_UI_ENABLED=${SWAGGER_UI_ENABLED} - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} - - ALLOWED_ORIGINS:${ALLOWED_ORIGINS} + - ALLOWED_ORIGINS=${ALLOWED_ORIGINS} depends_on: - consul - vault From 900cb6a00b291ec934e594a2a37243fa60b95b57 Mon Sep 17 00:00:00 2001 From: fatemeh imanipour Date: Sun, 31 May 2026 13:04:45 +0330 Subject: [PATCH 56/56] Setup custom server url for open apis --- .../co/nilin/opex/api/app/config/CorsConfig.kt | 2 -- .../nilin/opex/api/app/config/OpenApiConfig.kt | 17 +++++++++++++++-- api/api-app/src/main/resources/application.yml | 3 ++- .../co/nilin/opex/auth/config/OpenApiConfig.kt | 17 +++++++++++++++-- .../src/main/resources/application.yml | 2 ++ docker-compose.yml | 2 ++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt index 3e2d8793a..46abeeb1e 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/CorsConfig.kt @@ -20,8 +20,6 @@ class CorsConfig( ) { private val logger = LoggerFactory.getLogger(CorsConfig::class.java) - private val logger = LoggerFactory.getLogger(CorsConfig::class.java) - @Bean @Order(Ordered.HIGHEST_PRECEDENCE) diff --git a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt index ac4597ed7..26d82ad6d 100644 --- a/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt +++ b/api/api-app/src/main/kotlin/co/nilin/opex/api/app/config/OpenApiConfig.kt @@ -10,11 +10,14 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration -class OpenApiConfig() { +class OpenApiConfig( + @Value("\${app.openapi.server-url:}") + private val serverUrl: String +) { @Bean fun opexOpenApi(): OpenAPI { - return OpenAPI() + val openApi= OpenAPI() .info( Info() .title("Opex API") @@ -33,6 +36,16 @@ class OpenApiConfig() { .description("JWT Bearer token") ) ) + if (serverUrl.isNotBlank()) { + openApi.servers( + listOf( + Server() + .url(serverUrl) + .description("Public API server") + ) + ) + } + return openApi } } diff --git a/api/api-app/src/main/resources/application.yml b/api/api-app/src/main/resources/application.yml index 29bd59f40..61f39109e 100644 --- a/api/api-app/src/main/resources/application.yml +++ b/api/api-app/src/main/resources/application.yml @@ -152,7 +152,8 @@ app: cors: enabled: true allowed-origins: ${ALLOWED_ORIGINS:"http://localhost:8110"} - + openapi: + server-url: ${OPEN_API_SERVER_URL} # --- Swagger / SpringDoc (env-driven) --- springdoc: api-docs: diff --git a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt index f736645e7..6955a8c89 100644 --- a/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt +++ b/auth-gateway/auth-gateway-app/src/main/kotlin/co/nilin/opex/auth/config/OpenApiConfig.kt @@ -10,11 +10,14 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration(proxyBeanMethods = false) -class AuthGatewayOpenApiConfig() { +class AuthGatewayOpenApiConfig( + @Value("\${app.openapi.server-url:}") + private val serverUrl: String +) { @Bean fun authGatewayOpenApi(): OpenAPI { - return OpenAPI() + val openApi = OpenAPI() .info( Info() .title("Opex Auth Gateway API") @@ -32,5 +35,15 @@ class AuthGatewayOpenApiConfig() { .description("JWT Bearer token") ) ) + if (serverUrl.isNotBlank()) { + openApi.servers( + listOf( + Server() + .url(serverUrl) + .description("Public API server") + ) + ) + } + return openApi } } diff --git a/auth-gateway/auth-gateway-app/src/main/resources/application.yml b/auth-gateway/auth-gateway-app/src/main/resources/application.yml index 647bc0bda..04ceb4f9e 100644 --- a/auth-gateway/auth-gateway-app/src/main/resources/application.yml +++ b/auth-gateway/auth-gateway-app/src/main/resources/application.yml @@ -83,6 +83,8 @@ app: cors: enabled: true allowed-origins: ${ALLOWED_ORIGINS:"http://localhost:8110"} + openapi: + server-url: ${OPEN_API_SERVER_URL} # --- Swagger / SpringDoc (env-driven) --- springdoc: api-docs: diff --git a/docker-compose.yml b/docker-compose.yml index fe8b874f2..1874f04f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -427,6 +427,7 @@ services: - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} - ALLOWED_ORIGINS=${ALLOWED_ORIGINS} + - OPEN_API_SERVER_URL=${OPEN_API_SERVER_URL_AUTH} volumes: - auth-gateway-keys:/app/keys depends_on: @@ -527,6 +528,7 @@ services: - SWAGGER_AUTH_ENABLED=${SWAGGER_AUTH_ENABLED} - SWAGGER_AUTH_AUTHORITY=${SWAGGER_AUTH_AUTHORITY} - ALLOWED_ORIGINS=${ALLOWED_ORIGINS} + - OPEN_API_SERVER_URL=${OPEN_API_SERVER_URL_API} depends_on: - consul - vault