diff --git a/cmd/main.go b/cmd/main.go index 38797ae..a920fad 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -57,6 +57,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/atlas" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet/monitor" @@ -153,7 +154,9 @@ func main() { virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger) aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger) veliCLient := veli.NewClient(cfg, walletSvc) - veliVirtualGameService := veli.New(virtualGameSvc,vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), cfg) + veliVirtualGameService := veli.New(virtualGameSvc, vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), cfg) + atlasClient := atlas.NewClient(cfg, walletSvc) + atlasVirtualGameService := atlas.New(virtualGameSvc, vitualGameRepo, atlasClient, walletSvc, wallet.TransferStore(store), cfg) recommendationSvc := recommendation.NewService(recommendationRepo) chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY) @@ -244,6 +247,7 @@ func main() { // Initialize and start HTTP server app := httpserver.NewApp( + atlasVirtualGameService, veliVirtualGameService, telebirrSvc, arifpaySvc, diff --git a/docs/docs.go b/docs/docs.go index 1173278..a7f73c8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -24,6 +24,52 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/account": { + "post": { + "description": "Callback endpoint for Atlas game server to fetch player balance", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas Get User Data callback", + "parameters": [ + { + "description": "Get user data input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.AtlasGetUserDataRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.AtlasGetUserDataResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/api/v1/admin": { "get": { "description": "Get all Admins", @@ -696,9 +742,9 @@ const docTemplate = `{ } } }, - "/api/v1/auth/admin-login": { + "/api/v1/atlas/freespin": { "post": { - "description": "Login customer", + "description": "Sends a request to Atlas to create free spins/bets for a given player", "consumes": [ "application/json" ], @@ -706,17 +752,17 @@ const docTemplate = `{ "application/json" ], "tags": [ - "auth" + "Virtual Games - Atlas" ], - "summary": "Login customer", + "summary": "Create free spins for a player", "parameters": [ { - "description": "Login admin", - "name": "login", + "description": "Free spin input", + "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.loginAdminReq" + "$ref": "#/definitions/domain.FreeSpinRequest" } } ], @@ -724,33 +770,39 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.loginAdminRes" + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.FreeSpinResponse" + } + } + } + ] } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } }, - "401": { - "description": "Unauthorized", + "502": { + "description": "Bad Gateway", "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } } } } }, - "/api/v1/auth/customer-login": { + "/api/v1/atlas/init-game": { "post": { - "description": "Login customer", + "description": "Initializes a game session for the given player using Atlas virtual game provider", "consumes": [ "application/json" ], @@ -758,17 +810,17 @@ const docTemplate = `{ "application/json" ], "tags": [ - "auth" + "Virtual Games - Atlas" ], - "summary": "Login customer", + "summary": "Start an Atlas virtual game session", "parameters": [ { - "description": "Login customer", - "name": "login", + "description": "Start game input", + "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.loginCustomerReq" + "$ref": "#/definitions/domain.AtlasGameInitRequest" } } ], @@ -776,25 +828,31 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.loginCustomerRes" + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.AtlasGameInitResponse" + } + } + } + ] } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } }, - "401": { - "description": "Unauthorized", + "502": { + "description": "Bad Gateway", "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } } } @@ -2918,7 +2976,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.UpcomingEvent" + "$ref": "#/definitions/domain.BaseEvent" } } }, @@ -2957,7 +3015,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/domain.UpcomingEvent" + "$ref": "#/definitions/domain.BaseEvent" } }, "400": { @@ -3017,50 +3075,6 @@ const docTemplate = `{ } } }, - "/api/v1/events/{id}/flag": { - "put": { - "description": "Update the event featured", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "event" - ], - "summary": "update the event featured", - "parameters": [ - { - "type": "integer", - "description": "Event ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/issues": { "get": { "description": "Admin endpoint to list all reported issues with pagination", @@ -3304,7 +3318,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.League" + "$ref": "#/definitions/domain.BaseLeague" } } }, @@ -3323,112 +3337,6 @@ const docTemplate = `{ } } }, - "/api/v1/leagues/{id}/featured": { - "put": { - "description": "Set the league to featured/un-featured", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leagues" - ], - "summary": "Set the league to featured/un-featured", - "parameters": [ - { - "type": "integer", - "description": "League ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "League Featured Request", - "name": "active", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SetLeagueAsFeatured" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/leagues/{id}/set-active": { - "put": { - "description": "Set the league to active", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leagues" - ], - "summary": "Set the league to active", - "parameters": [ - { - "type": "integer", - "description": "League ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "League Active Request", - "name": "active", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SetLeagueActiveReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/logs": { "get": { "description": "Fetches application logs from MongoDB with pagination, level filtering, and search", @@ -3743,7 +3651,7 @@ const docTemplate = `{ }, "/api/v1/odds": { "get": { - "description": "Retrieve all prematch odds from the database", + "description": "Retrieve all odds from the database", "consumes": [ "application/json" ], @@ -3753,14 +3661,14 @@ const docTemplate = `{ "tags": [ "prematch" ], - "summary": "Retrieve all prematch odds", + "summary": "Retrieve all odds", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.Odd" + "$ref": "#/definitions/domain.OddMarketFilter" } } }, @@ -3813,7 +3721,7 @@ const docTemplate = `{ "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.Odd" + "$ref": "#/definitions/domain.OddMarketWithEventFilter" } } }, @@ -3932,6 +3840,82 @@ const docTemplate = `{ } } }, + "/api/v1/orchestrator/virtual-games": { + "get": { + "description": "Returns all virtual games with optional filters (category, search, pagination)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "VirtualGames - Orchestration" + ], + "summary": "List all virtual games", + "parameters": [ + { + "type": "string", + "description": "Filter by category", + "name": "category", + "in": "query" + }, + { + "type": "string", + "description": "Search by game name", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "Pagination limit", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Pagination offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.UnifiedGame" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/api/v1/referral/settings": { "get": { "security": [ @@ -5144,45 +5128,9 @@ const docTemplate = `{ } } }, - "/api/v1/sport/bet": { - "get": { - "description": "Gets all the bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets all bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, + "/api/v1/super-login": { "post": { - "description": "Creates a bet", + "description": "Login super-admin", "consumes": [ "application/json" ], @@ -5190,17 +5138,17 @@ const docTemplate = `{ "application/json" ], "tags": [ - "bet" + "auth" ], - "summary": "Create a bet", + "summary": "Login super-admin", "parameters": [ { - "description": "Creates bet", - "name": "createBet", + "description": "Login super-admin", + "name": "login", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/domain.CreateBetReq" + "$ref": "#/definitions/handlers.loginAdminReq" } } ], @@ -5208,7 +5156,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/domain.BetRes" + "$ref": "#/definitions/handlers.loginAdminRes" } }, "400": { @@ -5217,275 +5165,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.APIResponse" } }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/bet/fastcode": { - "post": { - "description": "Creates a bet with fast code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Create a bet with fast code", - "parameters": [ - { - "description": "Creates bet", - "name": "createBetWithFastCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateBetWithFastCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/bet/fastcode/{fast_code}": { - "get": { - "description": "Gets a single bet by fast_code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by fast_code", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "fast_code", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/bet/{id}": { - "get": { - "description": "Gets a single bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Deletes bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Deletes bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "patch": { - "description": "Updates the cashed out field", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Updates the cashed out field", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Updates Cashed Out", - "name": "updateCashOut", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateCashOutReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/random/bet": { - "post": { - "description": "Generate a random bet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Generate a random bet", - "parameters": [ - { - "description": "Create Random bet", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.RandomBetReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", + "401": { + "description": "Unauthorized", "schema": { "$ref": "#/definitions/response.APIResponse" } @@ -5673,164 +5354,6 @@ const docTemplate = `{ } } }, - "/api/v1/ticket": { - "get": { - "description": "Retrieve all tickets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get all tickets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.TicketRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a temporary ticket", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Create a temporary ticket", - "parameters": [ - { - "description": "Creates ticket", - "name": "createTicket", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateTicketReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.CreateTicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/ticket/{id}": { - "get": { - "description": "Retrieve ticket details by ticket ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get ticket by ID", - "parameters": [ - { - "type": "integer", - "description": "Ticket ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.TicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/top-leagues": { - "get": { - "description": "Retrieve all top leagues", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all top leagues", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.TopLeague" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/transfer/refill/:id": { "post": { "description": "Super Admin route to refill a wallet", @@ -5969,170 +5492,6 @@ const docTemplate = `{ } } }, - "/api/v1/user/admin-profile": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Get user profile", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user profile", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.AdminProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/bets": { - "get": { - "description": "Gets user bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Gets user bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/checkPhoneEmailExist": { - "post": { - "description": "Check if phone number or email exist", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Check if phone number or email exist", - "parameters": [ - { - "description": "Check phone number or email exist", - "name": "checkPhoneEmailExist", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/customer-profile": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Get user profile", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user profile", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CustomerProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/user/delete/{id}": { "delete": { "description": "Delete a user by their ID", @@ -6177,236 +5536,6 @@ const docTemplate = `{ } } }, - "/api/v1/user/register": { - "post": { - "description": "Register user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Register user", - "parameters": [ - { - "description": "Register user", - "name": "registerUser", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterUserReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/resetPassword": { - "post": { - "description": "Reset password", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Reset password", - "parameters": [ - { - "description": "Reset password", - "name": "resetPassword", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetPasswordReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/search": { - "post": { - "description": "Search for user using name or phone", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Search for user using name or phone", - "parameters": [ - { - "description": "Search for using his name or phone", - "name": "searchUserByNameOrPhone", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/sendRegisterCode": { - "post": { - "description": "Send register code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send register code", - "parameters": [ - { - "description": "Send register code", - "name": "registerCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/sendResetCode": { - "post": { - "description": "Send reset code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send reset code", - "parameters": [ - { - "description": "Send reset code", - "name": "resetCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/user/single/{id}": { "get": { "description": "Get a single user by id", @@ -6503,14 +5632,9 @@ const docTemplate = `{ } } }, - "/api/v1/user/wallet": { + "/api/v1/veli/credit-balances": { "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieve customer wallet details", + "description": "Fetches current credit balances per currency for the specified brand", "consumes": [ "application/json" ], @@ -6518,15 +5642,15 @@ const docTemplate = `{ "application/json" ], "tags": [ - "wallet" + "Virtual Games - VeliGames" ], - "summary": "Get customer wallet", + "summary": "Get VeliGames credit balances for a brand", "parameters": [ { - "type": "integer", - "description": "Company ID", - "name": "company_id", - "in": "header", + "type": "string", + "description": "Brand ID", + "name": "brandId", + "in": "query", "required": true } ], @@ -6534,19 +5658,34 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.CustomerWalletRes" + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.CreditBalance" + } + } + } + } + ] } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } }, - "500": { - "description": "Internal Server Error", + "502": { + "description": "Bad Gateway", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } } } @@ -7383,6 +6522,1657 @@ const docTemplate = `{ } } }, + "/api/v1/{tenant_slug}/admin-login": { + "post": { + "description": "Login customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Login customer", + "parameters": [ + { + "description": "Login admin", + "name": "login", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.loginAdminReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginAdminRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/customer-login": { + "post": { + "description": "Login customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Login customer", + "parameters": [ + { + "description": "Login customer", + "name": "login", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.loginCustomerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginCustomerRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/events": { + "get": { + "description": "Retrieve all upcoming events settings from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all upcoming events with settings", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "League ID Filter", + "name": "league_id", + "in": "query" + }, + { + "type": "string", + "description": "Sport ID Filter", + "name": "sport_id", + "in": "query" + }, + { + "type": "string", + "description": "Country Code Filter", + "name": "cc", + "in": "query" + }, + { + "type": "string", + "description": "Start Time", + "name": "first_start_time", + "in": "query" + }, + { + "type": "string", + "description": "End Time", + "name": "last_start_time", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BaseEvent" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/events/{id}/settings": { + "put": { + "description": "Update the event settings", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "event" + ], + "summary": "update the event settings", + "parameters": [ + { + "type": "integer", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/leagues": { + "get": { + "description": "Gets all leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Gets all leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BaseLeague" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/leagues/{id}/featured": { + "put": { + "description": "Set the league to featured/un-featured", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Set the league to featured/un-featured", + "parameters": [ + { + "type": "integer", + "description": "League ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "League Featured Request", + "name": "active", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SetLeagueAsFeatured" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/leagues/{id}/set-active": { + "put": { + "description": "Set the league to active", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Set the league to active", + "parameters": [ + { + "type": "integer", + "description": "League ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "League Active Request", + "name": "active", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SetLeagueActiveReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/odds": { + "get": { + "description": "Retrieve all odds from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all odds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.OddMarketFilter" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/odds/upcoming/{upcoming_id}": { + "get": { + "description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve prematch odds by upcoming ID (FI)", + "parameters": [ + { + "type": "string", + "description": "Upcoming Event ID (FI)", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Number of results to return (default: 10)", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Number of results to skip (default: 0)", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.OddMarketFilter" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/odds/upcoming/{upcoming_id}/market/{market_id}": { + "get": { + "description": "Retrieve raw odds records using a Market ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve raw odds by Market ID", + "parameters": [ + { + "type": "string", + "description": "Upcoming ID", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Market ID", + "name": "market_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.RawOddsByMarketID" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet": { + "get": { + "description": "Gets all the bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets all bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet", + "parameters": [ + { + "description": "Creates bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet/fastcode": { + "post": { + "description": "Creates a bet with fast code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet with fast code", + "parameters": [ + { + "description": "Creates bet", + "name": "createBetWithFastCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetWithFastCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet/fastcode/{fast_code}": { + "get": { + "description": "Gets a single bet by fast_code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets bet by fast_code", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "fast_code", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet/{id}": { + "get": { + "description": "Gets a single bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Deletes bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Deletes bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "patch": { + "description": "Updates the cashed out field", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Updates the cashed out field", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updates Cashed Out", + "name": "updateCashOut", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateCashOutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/random/bet": { + "post": { + "description": "Generate a random bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Generate a random bet", + "parameters": [ + { + "description": "Create Random bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RandomBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/ticket": { + "get": { + "description": "Retrieve all tickets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get all tickets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.TicketRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a temporary ticket", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Create a temporary ticket", + "parameters": [ + { + "description": "Creates ticket", + "name": "createTicket", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateTicketReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CreateTicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/ticket/{id}": { + "get": { + "description": "Retrieve ticket details by ticket ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get ticket by ID", + "parameters": [ + { + "type": "integer", + "description": "Ticket ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.TicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/top-leagues": { + "get": { + "description": "Retrieve all top leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all top leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.TopLeague" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/admin-profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get user profile", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user profile", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.AdminProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/bets": { + "get": { + "description": "Gets user bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Gets user bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/checkPhoneEmailExist": { + "post": { + "description": "Check if phone number or email exist", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Check if phone number or email exist", + "parameters": [ + { + "description": "Check phone number or email exist", + "name": "checkPhoneEmailExist", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/customer-profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get user profile", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user profile", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomerProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/register": { + "post": { + "description": "Register user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Register user", + "parameters": [ + { + "description": "Register user", + "name": "registerUser", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterUserReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/resetPassword": { + "post": { + "description": "Reset password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Reset password", + "parameters": [ + { + "description": "Reset password", + "name": "resetPassword", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetPasswordReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/search": { + "post": { + "description": "Search for user using name or phone", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Search for user using name or phone", + "parameters": [ + { + "description": "Search for using his name or phone", + "name": "searchUserByNameOrPhone", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/sendRegisterCode": { + "post": { + "description": "Send register code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send register code", + "parameters": [ + { + "description": "Send register code", + "name": "registerCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/sendResetCode": { + "post": { + "description": "Send reset code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send reset code", + "parameters": [ + { + "description": "Send reset code", + "name": "resetCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/wallet": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieve customer wallet details", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get customer wallet", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "company_id", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomerWalletRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}events/{id}": { + "get": { + "description": "Retrieve an upcoming event by ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve an upcoming by ID", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BaseEvent" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/betwin": { + "post": { + "description": "Processes a Bet and Win request from Atlas provider", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas BetWin callback", + "parameters": [ + { + "description": "Atlas BetWin input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.AtlasBetWinRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.AtlasBetWinResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/freespin": { + "post": { + "description": "Handles the result of a free spin/bet from the game server", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Free Spin/Bet result callback", + "parameters": [ + { + "description": "Free spin result input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.FreeSpinResultRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.FreeSpinResultResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/jackpot": { + "post": { + "description": "Handles the jackpot result from the game server", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Jackpot result callback", + "parameters": [ + { + "description": "Jackpot result input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.JackpotRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.JackpotResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/popok/games": { "get": { "description": "Retrieves the list of available PopOK slot games", @@ -7462,6 +8252,98 @@ const docTemplate = `{ } } }, + "/result": { + "post": { + "description": "Processes a round result from Atlas or other providers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas Round Result callback", + "parameters": [ + { + "description": "Round result input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RoundResultRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.RoundResultResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/rollback": { + "post": { + "description": "Processes a rollback request from Atlas or other providers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas Rollback callback", + "parameters": [ + { + "description": "Rollback request input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RollbackRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.RollbackResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/virtual-game/callback": { "post": { "description": "Processes callbacks from PopOK for game events", @@ -7659,6 +8541,108 @@ const docTemplate = `{ } } }, + "domain.AtlasBetWinRequest": { + "type": "object", + "properties": { + "betAmount": { + "type": "number" + }, + "casino_id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "type": "string" + }, + "winAmount": { + "type": "number" + } + } + }, + "domain.AtlasBetWinResponse": { + "type": "object", + "properties": { + "balance": { + "type": "number" + }, + "player_id": { + "type": "string" + } + } + }, + "domain.AtlasGameInitRequest": { + "type": "object", + "properties": { + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "language": { + "type": "string" + }, + "player_id": { + "type": "string" + } + } + }, + "domain.AtlasGameInitResponse": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, + "domain.AtlasGetUserDataRequest": { + "type": "object", + "properties": { + "casino_id": { + "type": "string" + }, + "game": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "session_id": { + "type": "string" + } + } + }, + "domain.AtlasGetUserDataResponse": { + "type": "object", + "properties": { + "balance": { + "type": "number" + }, + "player_id": { + "type": "string" + } + } + }, "domain.Bank": { "type": "object", "properties": { @@ -7712,6 +8696,115 @@ const docTemplate = `{ } } }, + "domain.BaseEvent": { + "type": "object", + "properties": { + "addedTime": { + "$ref": "#/definitions/domain.ValidInt" + }, + "awayTeam": { + "type": "string" + }, + "awayTeamID": { + "type": "integer" + }, + "awayTeamImage": { + "type": "string" + }, + "defaultIsActive": { + "type": "boolean" + }, + "defaultIsFeatured": { + "type": "boolean" + }, + "defaultWinningUpperLimit": { + "type": "integer" + }, + "fetchedAt": { + "type": "string" + }, + "homeTeam": { + "type": "string" + }, + "homeTeamID": { + "type": "integer" + }, + "homeTeamImage": { + "type": "string" + }, + "id": { + "type": "string" + }, + "isLive": { + "type": "boolean" + }, + "isMonitored": { + "type": "boolean" + }, + "leagueCC": { + "$ref": "#/definitions/domain.ValidString" + }, + "leagueID": { + "type": "integer" + }, + "leagueName": { + "type": "string" + }, + "matchMinute": { + "$ref": "#/definitions/domain.ValidInt" + }, + "matchName": { + "type": "string" + }, + "matchPeriod": { + "$ref": "#/definitions/domain.ValidInt" + }, + "score": { + "$ref": "#/definitions/domain.ValidString" + }, + "source": { + "$ref": "#/definitions/domain.EventSource" + }, + "sportID": { + "type": "integer" + }, + "startTime": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/domain.EventStatus" + }, + "timerStatus": { + "$ref": "#/definitions/domain.ValidString" + } + } + }, + "domain.BaseLeague": { + "type": "object", + "properties": { + "bet365ID": { + "$ref": "#/definitions/domain.ValidInt32" + }, + "countryCode": { + "$ref": "#/definitions/domain.ValidString" + }, + "defaultIsActive": { + "type": "boolean" + }, + "defaultIsFeatured": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "sportID": { + "type": "integer" + } + } + }, "domain.BetOutcome": { "type": "object", "properties": { @@ -7792,6 +8885,10 @@ const docTemplate = `{ "type": "boolean", "example": false }, + "company_id": { + "type": "integer", + "example": 1 + }, "created_at": { "type": "string", "example": "2025-04-08T12:00:00Z" @@ -8117,6 +9214,10 @@ const docTemplate = `{ "type": "string", "example": "CompanyName" }, + "slug": { + "type": "string", + "example": "slug" + }, "wallet_id": { "type": "integer", "example": 1 @@ -8311,6 +9412,20 @@ const docTemplate = `{ } } }, + "domain.CreditBalance": { + "type": "object", + "properties": { + "balance": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "threshold": { + "type": "number" + } + } + }, "domain.DashboardSummary": { "type": "object", "properties": { @@ -8487,6 +9602,23 @@ const docTemplate = `{ } } }, + "domain.EventSource": { + "type": "string", + "enum": [ + "b365api", + "bwin", + "bfair", + "1xbet", + "enetpulse" + ], + "x-enum-varnames": [ + "EVENT_SOURCE_BET365", + "EVENT_SOURCE_BWIN", + "EVENT_SOURCE_BETFAIR", + "EVENT_SOURCE_1XBET", + "EVENT_SOURCE_ENET" + ] + }, "domain.EventStatus": { "type": "string", "enum": [ @@ -8520,6 +9652,92 @@ const docTemplate = `{ "STATUS_REMOVED" ] }, + "domain.EventWithSettingsRes": { + "type": "object", + "properties": { + "added_time": { + "type": "integer" + }, + "away_team": { + "type": "string" + }, + "away_team_id": { + "type": "integer" + }, + "away_team_image": { + "type": "string" + }, + "fetched_at": { + "type": "string" + }, + "home_team": { + "type": "string" + }, + "home_team_id": { + "type": "integer" + }, + "home_team_image": { + "type": "string" + }, + "id": { + "type": "string" + }, + "is_active": { + "type": "boolean" + }, + "is_featured": { + "type": "boolean" + }, + "is_live": { + "type": "boolean" + }, + "is_monitored": { + "type": "boolean" + }, + "league_cc": { + "type": "string" + }, + "league_id": { + "type": "integer" + }, + "league_name": { + "type": "string" + }, + "match_minute": { + "type": "integer" + }, + "match_name": { + "type": "string" + }, + "match_period": { + "type": "integer" + }, + "score": { + "type": "string" + }, + "source": { + "$ref": "#/definitions/domain.EventSource" + }, + "sport_id": { + "type": "integer" + }, + "start_time": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/domain.EventStatus" + }, + "timer_status": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "winning_upper_limit": { + "type": "integer" + } + } + }, "domain.FavoriteGameRequest": { "type": "object", "properties": { @@ -8528,6 +9746,83 @@ const docTemplate = `{ } } }, + "domain.FreeSpinRequest": { + "type": "object", + "properties": { + "casino_id": { + "type": "string" + }, + "end_date": { + "description": "\"yyyy-mm-ddTHH:MM:SS+00:00\"", + "type": "string" + }, + "freespins_count": { + "description": "count of free spins/bets", + "type": "integer" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "domain.FreeSpinResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, + "domain.FreeSpinResultRequest": { + "type": "object", + "properties": { + "amount": { + "description": "win amount", + "type": "number" + }, + "casino_id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "type": "string" + } + } + }, + "domain.FreeSpinResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, "domain.GameListRequest": { "type": "object", "properties": { @@ -8807,6 +10102,10 @@ const docTemplate = `{ "type": "string", "example": "CompanyName" }, + "slug": { + "type": "string", + "example": "slug" + }, "wallet_id": { "type": "integer", "example": 1 @@ -8937,36 +10236,50 @@ const docTemplate = `{ } } }, - "domain.League": { + "domain.JackpotRequest": { "type": "object", "properties": { - "bet365_id": { - "type": "integer", - "example": 1121 + "amount": { + "description": "jackpot win", + "type": "number" }, - "cc": { - "type": "string", - "example": "uk" + "casino_id": { + "type": "string" }, - "id": { - "type": "integer", - "example": 1 + "currency": { + "type": "string" }, - "is_active": { - "type": "boolean", - "example": false + "details": { + "type": "string" }, - "is_featured": { - "type": "boolean", - "example": false + "game": { + "type": "string" }, - "name": { - "type": "string", - "example": "BPL" + "hash": { + "type": "string" }, - "sport_id": { - "type": "integer", - "example": 1 + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "type": "string" + } + } + }, + "domain.JackpotResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" } } }, @@ -9017,54 +10330,25 @@ const docTemplate = `{ } } }, - "domain.Odd": { + "domain.OddMarketFilter": { "type": "object", "properties": { - "category": { - "type": "string" + "limit": { + "$ref": "#/definitions/domain.ValidInt32" }, - "event_id": { - "type": "string" + "offset": { + "$ref": "#/definitions/domain.ValidInt32" + } + } + }, + "domain.OddMarketWithEventFilter": { + "type": "object", + "properties": { + "limit": { + "$ref": "#/definitions/domain.ValidInt32" }, - "fetched_at": { - "type": "string" - }, - "fi": { - "type": "string" - }, - "handicap": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "market_category": { - "type": "string" - }, - "market_id": { - "type": "string" - }, - "market_name": { - "type": "string" - }, - "market_type": { - "type": "string" - }, - "name": { - "type": "string" - }, - "odds_value": { - "type": "number" - }, - "raw_odds": { - "type": "array", - "items": {} - }, - "section": { - "type": "string" - }, - "source": { - "type": "string" + "offset": { + "$ref": "#/definitions/domain.ValidInt32" } } }, @@ -9295,6 +10579,9 @@ const docTemplate = `{ "domain.RawOddsByMarketID": { "type": "object", "properties": { + "expires_at": { + "type": "string" + }, "fetched_at": { "type": "string" }, @@ -9309,7 +10596,10 @@ const docTemplate = `{ }, "raw_odds": { "type": "array", - "items": {} + "items": { + "type": "object", + "additionalProperties": true + } } } }, @@ -9433,6 +10723,92 @@ const docTemplate = `{ "RoleCashier" ] }, + "domain.RollbackRequest": { + "type": "object", + "properties": { + "bet_transaction_id": { + "type": "string" + }, + "casino_id": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "domain.RollbackResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, + "domain.RoundResultRequest": { + "type": "object", + "properties": { + "amount": { + "description": "win amount", + "type": "number" + }, + "bet_transaction_id": { + "description": "from BET request", + "type": "string" + }, + "casino_id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "description": "new transaction id", + "type": "string" + } + } + }, + "domain.RoundResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, "domain.SantimPayCallbackPayload": { "type": "object", "properties": { @@ -9943,6 +11319,10 @@ const docTemplate = `{ "type": "number", "example": 100 }, + "company_id": { + "type": "integer", + "example": 1 + }, "id": { "type": "integer", "example": 1 @@ -9970,80 +11350,50 @@ const docTemplate = `{ } } }, - "domain.UpcomingEvent": { + "domain.UnifiedGame": { "type": "object", "properties": { - "away_kit_image": { - "description": "Kit or image for away team (optional)", + "bets": { + "type": "array", + "items": { + "type": "number" + } + }, + "category": { "type": "string" }, - "away_team": { - "description": "Away team name (can be empty/null)", + "deviceType": { "type": "string" }, - "away_team_id": { - "description": "Away team ID (can be empty/null)", - "type": "integer" - }, - "home_kit_image": { - "description": "Kit or image for home team (optional)", + "gameId": { "type": "string" }, - "home_team": { - "description": "Home team name (if available)", - "type": "string" - }, - "home_team_id": { - "description": "Home team ID", - "type": "integer" - }, - "id": { - "description": "Event ID", - "type": "string" - }, - "is_active": { - "description": "Whether the event is featured or not", + "hasDemo": { "type": "boolean" }, - "is_featured": { - "description": "Whether the event is featured or not", + "hasFreeBets": { "type": "boolean" }, - "league_cc": { - "description": "League country code", + "name": { "type": "string" }, - "league_id": { - "description": "League ID", - "type": "integer" - }, - "league_name": { - "description": "League name", + "provider": { "type": "string" }, - "match_name": { - "description": "Match or event name", + "providerId": { "type": "string" }, - "source": { - "description": "bet api provider (bet365, betfair)", - "type": "string" - }, - "sport_id": { - "description": "Sport ID", - "type": "integer" - }, - "start_time": { - "description": "Converted from \"time\" field in UNIX format", - "type": "string" + "rtp": { + "type": "number" }, "status": { - "description": "Match Status for event", - "allOf": [ - { - "$ref": "#/definitions/domain.EventStatus" - } - ] + "type": "integer" + }, + "thumbnail": { + "type": "string" + }, + "volatility": { + "type": "string" } } }, @@ -10077,6 +11427,39 @@ const docTemplate = `{ } } }, + "domain.ValidInt": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "integer" + } + } + }, + "domain.ValidInt32": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "integer" + } + } + }, + "domain.ValidString": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "string" + } + } + }, "domain.VerifyDirectDepositRequest": { "type": "object", "required": [ @@ -10757,7 +12140,7 @@ const docTemplate = `{ "events": { "type": "array", "items": { - "$ref": "#/definitions/domain.UpcomingEvent" + "$ref": "#/definitions/domain.EventWithSettingsRes" } }, "league_cc": { diff --git a/docs/swagger.json b/docs/swagger.json index ee0556a..672b70e 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -16,6 +16,52 @@ "version": "1.0.1" }, "paths": { + "/account": { + "post": { + "description": "Callback endpoint for Atlas game server to fetch player balance", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas Get User Data callback", + "parameters": [ + { + "description": "Get user data input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.AtlasGetUserDataRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.AtlasGetUserDataResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/api/v1/admin": { "get": { "description": "Get all Admins", @@ -688,9 +734,9 @@ } } }, - "/api/v1/auth/admin-login": { + "/api/v1/atlas/freespin": { "post": { - "description": "Login customer", + "description": "Sends a request to Atlas to create free spins/bets for a given player", "consumes": [ "application/json" ], @@ -698,17 +744,17 @@ "application/json" ], "tags": [ - "auth" + "Virtual Games - Atlas" ], - "summary": "Login customer", + "summary": "Create free spins for a player", "parameters": [ { - "description": "Login admin", - "name": "login", + "description": "Free spin input", + "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.loginAdminReq" + "$ref": "#/definitions/domain.FreeSpinRequest" } } ], @@ -716,33 +762,39 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.loginAdminRes" + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.FreeSpinResponse" + } + } + } + ] } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } }, - "401": { - "description": "Unauthorized", + "502": { + "description": "Bad Gateway", "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } } } } }, - "/api/v1/auth/customer-login": { + "/api/v1/atlas/init-game": { "post": { - "description": "Login customer", + "description": "Initializes a game session for the given player using Atlas virtual game provider", "consumes": [ "application/json" ], @@ -750,17 +802,17 @@ "application/json" ], "tags": [ - "auth" + "Virtual Games - Atlas" ], - "summary": "Login customer", + "summary": "Start an Atlas virtual game session", "parameters": [ { - "description": "Login customer", - "name": "login", + "description": "Start game input", + "name": "request", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.loginCustomerReq" + "$ref": "#/definitions/domain.AtlasGameInitRequest" } } ], @@ -768,25 +820,31 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.loginCustomerRes" + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.AtlasGameInitResponse" + } + } + } + ] } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } }, - "401": { - "description": "Unauthorized", + "502": { + "description": "Bad Gateway", "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } } } @@ -2910,7 +2968,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.UpcomingEvent" + "$ref": "#/definitions/domain.BaseEvent" } } }, @@ -2949,7 +3007,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/domain.UpcomingEvent" + "$ref": "#/definitions/domain.BaseEvent" } }, "400": { @@ -3009,50 +3067,6 @@ } } }, - "/api/v1/events/{id}/flag": { - "put": { - "description": "Update the event featured", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "event" - ], - "summary": "update the event featured", - "parameters": [ - { - "type": "integer", - "description": "Event ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/issues": { "get": { "description": "Admin endpoint to list all reported issues with pagination", @@ -3296,7 +3310,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.League" + "$ref": "#/definitions/domain.BaseLeague" } } }, @@ -3315,112 +3329,6 @@ } } }, - "/api/v1/leagues/{id}/featured": { - "put": { - "description": "Set the league to featured/un-featured", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leagues" - ], - "summary": "Set the league to featured/un-featured", - "parameters": [ - { - "type": "integer", - "description": "League ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "League Featured Request", - "name": "active", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SetLeagueAsFeatured" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/leagues/{id}/set-active": { - "put": { - "description": "Set the league to active", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "leagues" - ], - "summary": "Set the league to active", - "parameters": [ - { - "type": "integer", - "description": "League ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "League Active Request", - "name": "active", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SetLeagueActiveReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/logs": { "get": { "description": "Fetches application logs from MongoDB with pagination, level filtering, and search", @@ -3735,7 +3643,7 @@ }, "/api/v1/odds": { "get": { - "description": "Retrieve all prematch odds from the database", + "description": "Retrieve all odds from the database", "consumes": [ "application/json" ], @@ -3745,14 +3653,14 @@ "tags": [ "prematch" ], - "summary": "Retrieve all prematch odds", + "summary": "Retrieve all odds", "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.Odd" + "$ref": "#/definitions/domain.OddMarketFilter" } } }, @@ -3805,7 +3713,7 @@ "schema": { "type": "array", "items": { - "$ref": "#/definitions/domain.Odd" + "$ref": "#/definitions/domain.OddMarketWithEventFilter" } } }, @@ -3924,6 +3832,82 @@ } } }, + "/api/v1/orchestrator/virtual-games": { + "get": { + "description": "Returns all virtual games with optional filters (category, search, pagination)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "VirtualGames - Orchestration" + ], + "summary": "List all virtual games", + "parameters": [ + { + "type": "string", + "description": "Filter by category", + "name": "category", + "in": "query" + }, + { + "type": "string", + "description": "Search by game name", + "name": "search", + "in": "query" + }, + { + "type": "integer", + "description": "Pagination limit", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Pagination offset", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.UnifiedGame" + } + } + } + } + ] + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/api/v1/referral/settings": { "get": { "security": [ @@ -5136,45 +5120,9 @@ } } }, - "/api/v1/sport/bet": { - "get": { - "description": "Gets all the bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets all bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, + "/api/v1/super-login": { "post": { - "description": "Creates a bet", + "description": "Login super-admin", "consumes": [ "application/json" ], @@ -5182,17 +5130,17 @@ "application/json" ], "tags": [ - "bet" + "auth" ], - "summary": "Create a bet", + "summary": "Login super-admin", "parameters": [ { - "description": "Creates bet", - "name": "createBet", + "description": "Login super-admin", + "name": "login", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/domain.CreateBetReq" + "$ref": "#/definitions/handlers.loginAdminReq" } } ], @@ -5200,7 +5148,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/domain.BetRes" + "$ref": "#/definitions/handlers.loginAdminRes" } }, "400": { @@ -5209,275 +5157,8 @@ "$ref": "#/definitions/response.APIResponse" } }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/bet/fastcode": { - "post": { - "description": "Creates a bet with fast code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Create a bet with fast code", - "parameters": [ - { - "description": "Creates bet", - "name": "createBetWithFastCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateBetWithFastCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/bet/fastcode/{fast_code}": { - "get": { - "description": "Gets a single bet by fast_code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by fast_code", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "fast_code", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/bet/{id}": { - "get": { - "description": "Gets a single bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Gets bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "delete": { - "description": "Deletes bet by id", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Deletes bet by id", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "patch": { - "description": "Updates the cashed out field", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Updates the cashed out field", - "parameters": [ - { - "type": "integer", - "description": "Bet ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Updates Cashed Out", - "name": "updateCashOut", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.UpdateCashOutReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/sport/random/bet": { - "post": { - "description": "Generate a random bet", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "bet" - ], - "summary": "Generate a random bet", - "parameters": [ - { - "description": "Create Random bet", - "name": "createBet", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.RandomBetReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.BetRes" - } - }, - "400": { - "description": "Bad Request", + "401": { + "description": "Unauthorized", "schema": { "$ref": "#/definitions/response.APIResponse" } @@ -5665,164 +5346,6 @@ } } }, - "/api/v1/ticket": { - "get": { - "description": "Retrieve all tickets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get all tickets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.TicketRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - }, - "post": { - "description": "Creates a temporary ticket", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Create a temporary ticket", - "parameters": [ - { - "description": "Creates ticket", - "name": "createTicket", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/domain.CreateTicketReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.CreateTicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/ticket/{id}": { - "get": { - "description": "Retrieve ticket details by ticket ID", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "ticket" - ], - "summary": "Get ticket by ID", - "parameters": [ - { - "type": "integer", - "description": "Ticket ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/domain.TicketRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/top-leagues": { - "get": { - "description": "Retrieve all top leagues", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "prematch" - ], - "summary": "Retrieve all top leagues", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.TopLeague" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/transfer/refill/:id": { "post": { "description": "Super Admin route to refill a wallet", @@ -5961,170 +5484,6 @@ } } }, - "/api/v1/user/admin-profile": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Get user profile", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user profile", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.AdminProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/bets": { - "get": { - "description": "Gets user bets", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Gets user bets", - "responses": { - "200": { - "description": "OK", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/domain.BetRes" - } - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/checkPhoneEmailExist": { - "post": { - "description": "Check if phone number or email exist", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Check if phone number or email exist", - "parameters": [ - { - "description": "Check phone number or email exist", - "name": "checkPhoneEmailExist", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/customer-profile": { - "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Get user profile", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Get user profile", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.CustomerProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/user/delete/{id}": { "delete": { "description": "Delete a user by their ID", @@ -6169,236 +5528,6 @@ } } }, - "/api/v1/user/register": { - "post": { - "description": "Register user", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Register user", - "parameters": [ - { - "description": "Register user", - "name": "registerUser", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterUserReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/resetPassword": { - "post": { - "description": "Reset password", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Reset password", - "parameters": [ - { - "description": "Reset password", - "name": "resetPassword", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetPasswordReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/search": { - "post": { - "description": "Search for user using name or phone", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Search for user using name or phone", - "parameters": [ - { - "description": "Search for using his name or phone", - "name": "searchUserByNameOrPhone", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/handlers.UserProfileRes" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/sendRegisterCode": { - "post": { - "description": "Send register code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send register code", - "parameters": [ - { - "description": "Send register code", - "name": "registerCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.RegisterCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, - "/api/v1/user/sendResetCode": { - "post": { - "description": "Send reset code", - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "user" - ], - "summary": "Send reset code", - "parameters": [ - { - "description": "Send reset code", - "name": "resetCode", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handlers.ResetCodeReq" - } - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/response.APIResponse" - } - } - } - } - }, "/api/v1/user/single/{id}": { "get": { "description": "Get a single user by id", @@ -6495,14 +5624,9 @@ } } }, - "/api/v1/user/wallet": { + "/api/v1/veli/credit-balances": { "get": { - "security": [ - { - "Bearer": [] - } - ], - "description": "Retrieve customer wallet details", + "description": "Fetches current credit balances per currency for the specified brand", "consumes": [ "application/json" ], @@ -6510,15 +5634,15 @@ "application/json" ], "tags": [ - "wallet" + "Virtual Games - VeliGames" ], - "summary": "Get customer wallet", + "summary": "Get VeliGames credit balances for a brand", "parameters": [ { - "type": "integer", - "description": "Company ID", - "name": "company_id", - "in": "header", + "type": "string", + "description": "Brand ID", + "name": "brandId", + "in": "query", "required": true } ], @@ -6526,19 +5650,34 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.CustomerWalletRes" + "allOf": [ + { + "$ref": "#/definitions/domain.Response" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.CreditBalance" + } + } + } + } + ] } }, "400": { "description": "Bad Request", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } }, - "500": { - "description": "Internal Server Error", + "502": { + "description": "Bad Gateway", "schema": { - "$ref": "#/definitions/response.APIResponse" + "$ref": "#/definitions/domain.ErrorResponse" } } } @@ -7375,6 +6514,1657 @@ } } }, + "/api/v1/{tenant_slug}/admin-login": { + "post": { + "description": "Login customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Login customer", + "parameters": [ + { + "description": "Login admin", + "name": "login", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.loginAdminReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginAdminRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/customer-login": { + "post": { + "description": "Login customer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "auth" + ], + "summary": "Login customer", + "parameters": [ + { + "description": "Login customer", + "name": "login", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.loginCustomerReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.loginCustomerRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/events": { + "get": { + "description": "Retrieve all upcoming events settings from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all upcoming events with settings", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query" + }, + { + "type": "string", + "description": "League ID Filter", + "name": "league_id", + "in": "query" + }, + { + "type": "string", + "description": "Sport ID Filter", + "name": "sport_id", + "in": "query" + }, + { + "type": "string", + "description": "Country Code Filter", + "name": "cc", + "in": "query" + }, + { + "type": "string", + "description": "Start Time", + "name": "first_start_time", + "in": "query" + }, + { + "type": "string", + "description": "End Time", + "name": "last_start_time", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BaseEvent" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/events/{id}/settings": { + "put": { + "description": "Update the event settings", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "event" + ], + "summary": "update the event settings", + "parameters": [ + { + "type": "integer", + "description": "Event ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/leagues": { + "get": { + "description": "Gets all leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Gets all leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BaseLeague" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/leagues/{id}/featured": { + "put": { + "description": "Set the league to featured/un-featured", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Set the league to featured/un-featured", + "parameters": [ + { + "type": "integer", + "description": "League ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "League Featured Request", + "name": "active", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SetLeagueAsFeatured" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/leagues/{id}/set-active": { + "put": { + "description": "Set the league to active", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "leagues" + ], + "summary": "Set the league to active", + "parameters": [ + { + "type": "integer", + "description": "League ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "League Active Request", + "name": "active", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SetLeagueActiveReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/odds": { + "get": { + "description": "Retrieve all odds from the database", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all odds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.OddMarketFilter" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/odds/upcoming/{upcoming_id}": { + "get": { + "description": "Retrieve prematch odds by upcoming event ID (FI from Bet365) with optional pagination", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve prematch odds by upcoming ID (FI)", + "parameters": [ + { + "type": "string", + "description": "Upcoming Event ID (FI)", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Number of results to return (default: 10)", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "Number of results to skip (default: 0)", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.OddMarketFilter" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/odds/upcoming/{upcoming_id}/market/{market_id}": { + "get": { + "description": "Retrieve raw odds records using a Market ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve raw odds by Market ID", + "parameters": [ + { + "type": "string", + "description": "Upcoming ID", + "name": "upcoming_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Market ID", + "name": "market_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.RawOddsByMarketID" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet": { + "get": { + "description": "Gets all the bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets all bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet", + "parameters": [ + { + "description": "Creates bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet/fastcode": { + "post": { + "description": "Creates a bet with fast code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Create a bet with fast code", + "parameters": [ + { + "description": "Creates bet", + "name": "createBetWithFastCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateBetWithFastCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet/fastcode/{fast_code}": { + "get": { + "description": "Gets a single bet by fast_code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets bet by fast_code", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "fast_code", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/bet/{id}": { + "get": { + "description": "Gets a single bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Gets bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "delete": { + "description": "Deletes bet by id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Deletes bet by id", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "patch": { + "description": "Updates the cashed out field", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Updates the cashed out field", + "parameters": [ + { + "type": "integer", + "description": "Bet ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Updates Cashed Out", + "name": "updateCashOut", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.UpdateCashOutReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/sport/random/bet": { + "post": { + "description": "Generate a random bet", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "bet" + ], + "summary": "Generate a random bet", + "parameters": [ + { + "description": "Create Random bet", + "name": "createBet", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RandomBetReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BetRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/ticket": { + "get": { + "description": "Retrieve all tickets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get all tickets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.TicketRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + }, + "post": { + "description": "Creates a temporary ticket", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Create a temporary ticket", + "parameters": [ + { + "description": "Creates ticket", + "name": "createTicket", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.CreateTicketReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.CreateTicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/ticket/{id}": { + "get": { + "description": "Retrieve ticket details by ticket ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ticket" + ], + "summary": "Get ticket by ID", + "parameters": [ + { + "type": "integer", + "description": "Ticket ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.TicketRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/top-leagues": { + "get": { + "description": "Retrieve all top leagues", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve all top leagues", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/handlers.TopLeague" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/admin-profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get user profile", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user profile", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.AdminProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/bets": { + "get": { + "description": "Gets user bets", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Gets user bets", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.BetRes" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/checkPhoneEmailExist": { + "post": { + "description": "Check if phone number or email exist", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Check if phone number or email exist", + "parameters": [ + { + "description": "Check phone number or email exist", + "name": "checkPhoneEmailExist", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CheckPhoneEmailExistRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/customer-profile": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Get user profile", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Get user profile", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomerProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/register": { + "post": { + "description": "Register user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Register user", + "parameters": [ + { + "description": "Register user", + "name": "registerUser", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterUserReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/resetPassword": { + "post": { + "description": "Reset password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Reset password", + "parameters": [ + { + "description": "Reset password", + "name": "resetPassword", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetPasswordReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/search": { + "post": { + "description": "Search for user using name or phone", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Search for user using name or phone", + "parameters": [ + { + "description": "Search for using his name or phone", + "name": "searchUserByNameOrPhone", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.SearchUserByNameOrPhoneReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.UserProfileRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/sendRegisterCode": { + "post": { + "description": "Send register code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send register code", + "parameters": [ + { + "description": "Send register code", + "name": "registerCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.RegisterCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/sendResetCode": { + "post": { + "description": "Send reset code", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "user" + ], + "summary": "Send reset code", + "parameters": [ + { + "description": "Send reset code", + "name": "resetCode", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handlers.ResetCodeReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}/user/wallet": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Retrieve customer wallet details", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "wallet" + ], + "summary": "Get customer wallet", + "parameters": [ + { + "type": "integer", + "description": "Company ID", + "name": "company_id", + "in": "header", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handlers.CustomerWalletRes" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/api/v1/{tenant_slug}events/{id}": { + "get": { + "description": "Retrieve an upcoming event by ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "prematch" + ], + "summary": "Retrieve an upcoming by ID", + "parameters": [ + { + "type": "string", + "description": "ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.BaseEvent" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.APIResponse" + } + } + } + } + }, + "/betwin": { + "post": { + "description": "Processes a Bet and Win request from Atlas provider", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas BetWin callback", + "parameters": [ + { + "description": "Atlas BetWin input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.AtlasBetWinRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.AtlasBetWinResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/freespin": { + "post": { + "description": "Handles the result of a free spin/bet from the game server", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Free Spin/Bet result callback", + "parameters": [ + { + "description": "Free spin result input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.FreeSpinResultRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.FreeSpinResultResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/jackpot": { + "post": { + "description": "Handles the jackpot result from the game server", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Jackpot result callback", + "parameters": [ + { + "description": "Jackpot result input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.JackpotRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.JackpotResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/popok/games": { "get": { "description": "Retrieves the list of available PopOK slot games", @@ -7454,6 +8244,98 @@ } } }, + "/result": { + "post": { + "description": "Processes a round result from Atlas or other providers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas Round Result callback", + "parameters": [ + { + "description": "Round result input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RoundResultRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.RoundResultResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, + "/rollback": { + "post": { + "description": "Processes a rollback request from Atlas or other providers", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Virtual Games - Atlas" + ], + "summary": "Atlas Rollback callback", + "parameters": [ + { + "description": "Rollback request input", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.RollbackRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/domain.RollbackResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + }, + "502": { + "description": "Bad Gateway", + "schema": { + "$ref": "#/definitions/domain.ErrorResponse" + } + } + } + } + }, "/virtual-game/callback": { "post": { "description": "Processes callbacks from PopOK for game events", @@ -7651,6 +8533,108 @@ } } }, + "domain.AtlasBetWinRequest": { + "type": "object", + "properties": { + "betAmount": { + "type": "number" + }, + "casino_id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "type": "string" + }, + "winAmount": { + "type": "number" + } + } + }, + "domain.AtlasBetWinResponse": { + "type": "object", + "properties": { + "balance": { + "type": "number" + }, + "player_id": { + "type": "string" + } + } + }, + "domain.AtlasGameInitRequest": { + "type": "object", + "properties": { + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "language": { + "type": "string" + }, + "player_id": { + "type": "string" + } + } + }, + "domain.AtlasGameInitResponse": { + "type": "object", + "properties": { + "url": { + "type": "string" + } + } + }, + "domain.AtlasGetUserDataRequest": { + "type": "object", + "properties": { + "casino_id": { + "type": "string" + }, + "game": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "session_id": { + "type": "string" + } + } + }, + "domain.AtlasGetUserDataResponse": { + "type": "object", + "properties": { + "balance": { + "type": "number" + }, + "player_id": { + "type": "string" + } + } + }, "domain.Bank": { "type": "object", "properties": { @@ -7704,6 +8688,115 @@ } } }, + "domain.BaseEvent": { + "type": "object", + "properties": { + "addedTime": { + "$ref": "#/definitions/domain.ValidInt" + }, + "awayTeam": { + "type": "string" + }, + "awayTeamID": { + "type": "integer" + }, + "awayTeamImage": { + "type": "string" + }, + "defaultIsActive": { + "type": "boolean" + }, + "defaultIsFeatured": { + "type": "boolean" + }, + "defaultWinningUpperLimit": { + "type": "integer" + }, + "fetchedAt": { + "type": "string" + }, + "homeTeam": { + "type": "string" + }, + "homeTeamID": { + "type": "integer" + }, + "homeTeamImage": { + "type": "string" + }, + "id": { + "type": "string" + }, + "isLive": { + "type": "boolean" + }, + "isMonitored": { + "type": "boolean" + }, + "leagueCC": { + "$ref": "#/definitions/domain.ValidString" + }, + "leagueID": { + "type": "integer" + }, + "leagueName": { + "type": "string" + }, + "matchMinute": { + "$ref": "#/definitions/domain.ValidInt" + }, + "matchName": { + "type": "string" + }, + "matchPeriod": { + "$ref": "#/definitions/domain.ValidInt" + }, + "score": { + "$ref": "#/definitions/domain.ValidString" + }, + "source": { + "$ref": "#/definitions/domain.EventSource" + }, + "sportID": { + "type": "integer" + }, + "startTime": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/domain.EventStatus" + }, + "timerStatus": { + "$ref": "#/definitions/domain.ValidString" + } + } + }, + "domain.BaseLeague": { + "type": "object", + "properties": { + "bet365ID": { + "$ref": "#/definitions/domain.ValidInt32" + }, + "countryCode": { + "$ref": "#/definitions/domain.ValidString" + }, + "defaultIsActive": { + "type": "boolean" + }, + "defaultIsFeatured": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "sportID": { + "type": "integer" + } + } + }, "domain.BetOutcome": { "type": "object", "properties": { @@ -7784,6 +8877,10 @@ "type": "boolean", "example": false }, + "company_id": { + "type": "integer", + "example": 1 + }, "created_at": { "type": "string", "example": "2025-04-08T12:00:00Z" @@ -8109,6 +9206,10 @@ "type": "string", "example": "CompanyName" }, + "slug": { + "type": "string", + "example": "slug" + }, "wallet_id": { "type": "integer", "example": 1 @@ -8303,6 +9404,20 @@ } } }, + "domain.CreditBalance": { + "type": "object", + "properties": { + "balance": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "threshold": { + "type": "number" + } + } + }, "domain.DashboardSummary": { "type": "object", "properties": { @@ -8479,6 +9594,23 @@ } } }, + "domain.EventSource": { + "type": "string", + "enum": [ + "b365api", + "bwin", + "bfair", + "1xbet", + "enetpulse" + ], + "x-enum-varnames": [ + "EVENT_SOURCE_BET365", + "EVENT_SOURCE_BWIN", + "EVENT_SOURCE_BETFAIR", + "EVENT_SOURCE_1XBET", + "EVENT_SOURCE_ENET" + ] + }, "domain.EventStatus": { "type": "string", "enum": [ @@ -8512,6 +9644,92 @@ "STATUS_REMOVED" ] }, + "domain.EventWithSettingsRes": { + "type": "object", + "properties": { + "added_time": { + "type": "integer" + }, + "away_team": { + "type": "string" + }, + "away_team_id": { + "type": "integer" + }, + "away_team_image": { + "type": "string" + }, + "fetched_at": { + "type": "string" + }, + "home_team": { + "type": "string" + }, + "home_team_id": { + "type": "integer" + }, + "home_team_image": { + "type": "string" + }, + "id": { + "type": "string" + }, + "is_active": { + "type": "boolean" + }, + "is_featured": { + "type": "boolean" + }, + "is_live": { + "type": "boolean" + }, + "is_monitored": { + "type": "boolean" + }, + "league_cc": { + "type": "string" + }, + "league_id": { + "type": "integer" + }, + "league_name": { + "type": "string" + }, + "match_minute": { + "type": "integer" + }, + "match_name": { + "type": "string" + }, + "match_period": { + "type": "integer" + }, + "score": { + "type": "string" + }, + "source": { + "$ref": "#/definitions/domain.EventSource" + }, + "sport_id": { + "type": "integer" + }, + "start_time": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/domain.EventStatus" + }, + "timer_status": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "winning_upper_limit": { + "type": "integer" + } + } + }, "domain.FavoriteGameRequest": { "type": "object", "properties": { @@ -8520,6 +9738,83 @@ } } }, + "domain.FreeSpinRequest": { + "type": "object", + "properties": { + "casino_id": { + "type": "string" + }, + "end_date": { + "description": "\"yyyy-mm-ddTHH:MM:SS+00:00\"", + "type": "string" + }, + "freespins_count": { + "description": "count of free spins/bets", + "type": "integer" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "domain.FreeSpinResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, + "domain.FreeSpinResultRequest": { + "type": "object", + "properties": { + "amount": { + "description": "win amount", + "type": "number" + }, + "casino_id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "type": "string" + } + } + }, + "domain.FreeSpinResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, "domain.GameListRequest": { "type": "object", "properties": { @@ -8799,6 +10094,10 @@ "type": "string", "example": "CompanyName" }, + "slug": { + "type": "string", + "example": "slug" + }, "wallet_id": { "type": "integer", "example": 1 @@ -8929,36 +10228,50 @@ } } }, - "domain.League": { + "domain.JackpotRequest": { "type": "object", "properties": { - "bet365_id": { - "type": "integer", - "example": 1121 + "amount": { + "description": "jackpot win", + "type": "number" }, - "cc": { - "type": "string", - "example": "uk" + "casino_id": { + "type": "string" }, - "id": { - "type": "integer", - "example": 1 + "currency": { + "type": "string" }, - "is_active": { - "type": "boolean", - "example": false + "details": { + "type": "string" }, - "is_featured": { - "type": "boolean", - "example": false + "game": { + "type": "string" }, - "name": { - "type": "string", - "example": "BPL" + "hash": { + "type": "string" }, - "sport_id": { - "type": "integer", - "example": 1 + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "type": "string" + } + } + }, + "domain.JackpotResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" } } }, @@ -9009,54 +10322,25 @@ } } }, - "domain.Odd": { + "domain.OddMarketFilter": { "type": "object", "properties": { - "category": { - "type": "string" + "limit": { + "$ref": "#/definitions/domain.ValidInt32" }, - "event_id": { - "type": "string" + "offset": { + "$ref": "#/definitions/domain.ValidInt32" + } + } + }, + "domain.OddMarketWithEventFilter": { + "type": "object", + "properties": { + "limit": { + "$ref": "#/definitions/domain.ValidInt32" }, - "fetched_at": { - "type": "string" - }, - "fi": { - "type": "string" - }, - "handicap": { - "type": "string" - }, - "is_active": { - "type": "boolean" - }, - "market_category": { - "type": "string" - }, - "market_id": { - "type": "string" - }, - "market_name": { - "type": "string" - }, - "market_type": { - "type": "string" - }, - "name": { - "type": "string" - }, - "odds_value": { - "type": "number" - }, - "raw_odds": { - "type": "array", - "items": {} - }, - "section": { - "type": "string" - }, - "source": { - "type": "string" + "offset": { + "$ref": "#/definitions/domain.ValidInt32" } } }, @@ -9287,6 +10571,9 @@ "domain.RawOddsByMarketID": { "type": "object", "properties": { + "expires_at": { + "type": "string" + }, "fetched_at": { "type": "string" }, @@ -9301,7 +10588,10 @@ }, "raw_odds": { "type": "array", - "items": {} + "items": { + "type": "object", + "additionalProperties": true + } } } }, @@ -9425,6 +10715,92 @@ "RoleCashier" ] }, + "domain.RollbackRequest": { + "type": "object", + "properties": { + "bet_transaction_id": { + "type": "string" + }, + "casino_id": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + } + }, + "domain.RollbackResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, + "domain.RoundResultRequest": { + "type": "object", + "properties": { + "amount": { + "description": "win amount", + "type": "number" + }, + "bet_transaction_id": { + "description": "from BET request", + "type": "string" + }, + "casino_id": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "game": { + "type": "string" + }, + "hash": { + "type": "string" + }, + "player_id": { + "type": "string" + }, + "round_id": { + "type": "integer" + }, + "session_id": { + "type": "string" + }, + "timestamp": { + "type": "string" + }, + "transaction_id": { + "description": "new transaction id", + "type": "string" + } + } + }, + "domain.RoundResultResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + } + } + }, "domain.SantimPayCallbackPayload": { "type": "object", "properties": { @@ -9935,6 +11311,10 @@ "type": "number", "example": 100 }, + "company_id": { + "type": "integer", + "example": 1 + }, "id": { "type": "integer", "example": 1 @@ -9962,80 +11342,50 @@ } } }, - "domain.UpcomingEvent": { + "domain.UnifiedGame": { "type": "object", "properties": { - "away_kit_image": { - "description": "Kit or image for away team (optional)", + "bets": { + "type": "array", + "items": { + "type": "number" + } + }, + "category": { "type": "string" }, - "away_team": { - "description": "Away team name (can be empty/null)", + "deviceType": { "type": "string" }, - "away_team_id": { - "description": "Away team ID (can be empty/null)", - "type": "integer" - }, - "home_kit_image": { - "description": "Kit or image for home team (optional)", + "gameId": { "type": "string" }, - "home_team": { - "description": "Home team name (if available)", - "type": "string" - }, - "home_team_id": { - "description": "Home team ID", - "type": "integer" - }, - "id": { - "description": "Event ID", - "type": "string" - }, - "is_active": { - "description": "Whether the event is featured or not", + "hasDemo": { "type": "boolean" }, - "is_featured": { - "description": "Whether the event is featured or not", + "hasFreeBets": { "type": "boolean" }, - "league_cc": { - "description": "League country code", + "name": { "type": "string" }, - "league_id": { - "description": "League ID", - "type": "integer" - }, - "league_name": { - "description": "League name", + "provider": { "type": "string" }, - "match_name": { - "description": "Match or event name", + "providerId": { "type": "string" }, - "source": { - "description": "bet api provider (bet365, betfair)", - "type": "string" - }, - "sport_id": { - "description": "Sport ID", - "type": "integer" - }, - "start_time": { - "description": "Converted from \"time\" field in UNIX format", - "type": "string" + "rtp": { + "type": "number" }, "status": { - "description": "Match Status for event", - "allOf": [ - { - "$ref": "#/definitions/domain.EventStatus" - } - ] + "type": "integer" + }, + "thumbnail": { + "type": "string" + }, + "volatility": { + "type": "string" } } }, @@ -10069,6 +11419,39 @@ } } }, + "domain.ValidInt": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "integer" + } + } + }, + "domain.ValidInt32": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "integer" + } + } + }, + "domain.ValidString": { + "type": "object", + "properties": { + "valid": { + "type": "boolean" + }, + "value": { + "type": "string" + } + } + }, "domain.VerifyDirectDepositRequest": { "type": "object", "required": [ @@ -10749,7 +12132,7 @@ "events": { "type": "array", "items": { - "$ref": "#/definitions/domain.UpcomingEvent" + "$ref": "#/definitions/domain.EventWithSettingsRes" } }, "league_cc": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 60cf75b..b54bc7b 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -60,6 +60,72 @@ definitions: transactionId: type: string type: object + domain.AtlasBetWinRequest: + properties: + betAmount: + type: number + casino_id: + type: string + currency: + type: string + game: + type: string + hash: + type: string + player_id: + type: string + round_id: + type: integer + session_id: + type: string + timestamp: + type: string + transaction_id: + type: string + winAmount: + type: number + type: object + domain.AtlasBetWinResponse: + properties: + balance: + type: number + player_id: + type: string + type: object + domain.AtlasGameInitRequest: + properties: + currency: + type: string + game: + type: string + language: + type: string + player_id: + type: string + type: object + domain.AtlasGameInitResponse: + properties: + url: + type: string + type: object + domain.AtlasGetUserDataRequest: + properties: + casino_id: + type: string + game: + type: string + player_id: + type: string + session_id: + type: string + type: object + domain.AtlasGetUserDataResponse: + properties: + balance: + type: number + player_id: + type: string + type: object domain.Bank: properties: acct_length: @@ -96,6 +162,78 @@ definitions: updated_at: type: string type: object + domain.BaseEvent: + properties: + addedTime: + $ref: '#/definitions/domain.ValidInt' + awayTeam: + type: string + awayTeamID: + type: integer + awayTeamImage: + type: string + defaultIsActive: + type: boolean + defaultIsFeatured: + type: boolean + defaultWinningUpperLimit: + type: integer + fetchedAt: + type: string + homeTeam: + type: string + homeTeamID: + type: integer + homeTeamImage: + type: string + id: + type: string + isLive: + type: boolean + isMonitored: + type: boolean + leagueCC: + $ref: '#/definitions/domain.ValidString' + leagueID: + type: integer + leagueName: + type: string + matchMinute: + $ref: '#/definitions/domain.ValidInt' + matchName: + type: string + matchPeriod: + $ref: '#/definitions/domain.ValidInt' + score: + $ref: '#/definitions/domain.ValidString' + source: + $ref: '#/definitions/domain.EventSource' + sportID: + type: integer + startTime: + type: string + status: + $ref: '#/definitions/domain.EventStatus' + timerStatus: + $ref: '#/definitions/domain.ValidString' + type: object + domain.BaseLeague: + properties: + bet365ID: + $ref: '#/definitions/domain.ValidInt32' + countryCode: + $ref: '#/definitions/domain.ValidString' + defaultIsActive: + type: boolean + defaultIsFeatured: + type: boolean + id: + type: integer + name: + type: string + sportID: + type: integer + type: object domain.BetOutcome: properties: away_team_name: @@ -153,6 +291,9 @@ definitions: cashed_out: example: false type: boolean + company_id: + example: 1 + type: integer created_at: example: "2025-04-08T12:00:00Z" type: string @@ -377,6 +518,9 @@ definitions: name: example: CompanyName type: string + slug: + example: slug + type: string wallet_id: example: 1 type: integer @@ -514,6 +658,15 @@ definitions: example: 1234 type: integer type: object + domain.CreditBalance: + properties: + balance: + type: number + currency: + type: string + threshold: + type: number + type: object domain.DashboardSummary: properties: active_admins: @@ -631,6 +784,20 @@ definitions: message: type: string type: object + domain.EventSource: + enum: + - b365api + - bwin + - bfair + - 1xbet + - enetpulse + type: string + x-enum-varnames: + - EVENT_SOURCE_BET365 + - EVENT_SOURCE_BWIN + - EVENT_SOURCE_BETFAIR + - EVENT_SOURCE_1XBET + - EVENT_SOURCE_ENET domain.EventStatus: enum: - upcoming @@ -661,11 +828,119 @@ definitions: - STATUS_SUSPENDED - STATUS_DECIDED_BY_FA - STATUS_REMOVED + domain.EventWithSettingsRes: + properties: + added_time: + type: integer + away_team: + type: string + away_team_id: + type: integer + away_team_image: + type: string + fetched_at: + type: string + home_team: + type: string + home_team_id: + type: integer + home_team_image: + type: string + id: + type: string + is_active: + type: boolean + is_featured: + type: boolean + is_live: + type: boolean + is_monitored: + type: boolean + league_cc: + type: string + league_id: + type: integer + league_name: + type: string + match_minute: + type: integer + match_name: + type: string + match_period: + type: integer + score: + type: string + source: + $ref: '#/definitions/domain.EventSource' + sport_id: + type: integer + start_time: + type: string + status: + $ref: '#/definitions/domain.EventStatus' + timer_status: + type: string + updated_at: + type: string + winning_upper_limit: + type: integer + type: object domain.FavoriteGameRequest: properties: game_id: type: integer type: object + domain.FreeSpinRequest: + properties: + casino_id: + type: string + end_date: + description: '"yyyy-mm-ddTHH:MM:SS+00:00"' + type: string + freespins_count: + description: count of free spins/bets + type: integer + hash: + type: string + player_id: + type: string + timestamp: + type: string + type: object + domain.FreeSpinResponse: + properties: + success: + type: boolean + type: object + domain.FreeSpinResultRequest: + properties: + amount: + description: win amount + type: number + casino_id: + type: string + currency: + type: string + game: + type: string + hash: + type: string + player_id: + type: string + round_id: + type: integer + session_id: + type: string + timestamp: + type: string + transaction_id: + type: string + type: object + domain.FreeSpinResultResponse: + properties: + success: + type: boolean + type: object domain.GameListRequest: properties: brandId: @@ -856,6 +1131,9 @@ definitions: name: example: CompanyName type: string + slug: + example: slug + type: string wallet_id: example: 1 type: integer @@ -940,29 +1218,36 @@ definitions: status: type: string type: object - domain.League: + domain.JackpotRequest: properties: - bet365_id: - example: 1121 - type: integer - cc: - example: uk + amount: + description: jackpot win + type: number + casino_id: type: string - id: - example: 1 - type: integer - is_active: - example: false - type: boolean - is_featured: - example: false - type: boolean - name: - example: BPL + currency: type: string - sport_id: - example: 1 + details: + type: string + game: + type: string + hash: + type: string + player_id: + type: string + round_id: type: integer + session_id: + type: string + timestamp: + type: string + transaction_id: + type: string + type: object + domain.JackpotResponse: + properties: + success: + type: boolean type: object domain.LogEntry: properties: @@ -995,39 +1280,19 @@ definitions: pagination: $ref: '#/definitions/domain.Pagination' type: object - domain.Odd: + domain.OddMarketFilter: properties: - category: - type: string - event_id: - type: string - fetched_at: - type: string - fi: - type: string - handicap: - type: string - is_active: - type: boolean - market_category: - type: string - market_id: - type: string - market_name: - type: string - market_type: - type: string - name: - type: string - odds_value: - type: number - raw_odds: - items: {} - type: array - section: - type: string - source: - type: string + limit: + $ref: '#/definitions/domain.ValidInt32' + offset: + $ref: '#/definitions/domain.ValidInt32' + type: object + domain.OddMarketWithEventFilter: + properties: + limit: + $ref: '#/definitions/domain.ValidInt32' + offset: + $ref: '#/definitions/domain.ValidInt32' type: object domain.OutcomeStatus: enum: @@ -1187,6 +1452,8 @@ definitions: type: object domain.RawOddsByMarketID: properties: + expires_at: + type: string fetched_at: type: string handicap: @@ -1196,7 +1463,9 @@ definitions: market_name: type: string raw_odds: - items: {} + items: + additionalProperties: true + type: object type: array type: object domain.ReferralSettings: @@ -1281,6 +1550,63 @@ definitions: - RoleBranchManager - RoleCustomer - RoleCashier + domain.RollbackRequest: + properties: + bet_transaction_id: + type: string + casino_id: + type: string + game: + type: string + hash: + type: string + player_id: + type: string + round_id: + type: integer + session_id: + type: string + timestamp: + type: string + type: object + domain.RollbackResponse: + properties: + success: + type: boolean + type: object + domain.RoundResultRequest: + properties: + amount: + description: win amount + type: number + bet_transaction_id: + description: from BET request + type: string + casino_id: + type: string + currency: + type: string + game: + type: string + hash: + type: string + player_id: + type: string + round_id: + type: integer + session_id: + type: string + timestamp: + type: string + transaction_id: + description: new transaction id + type: string + type: object + domain.RoundResultResponse: + properties: + success: + type: boolean + type: object domain.SantimPayCallbackPayload: properties: accountNumber: @@ -1637,6 +1963,9 @@ definitions: amount: example: 100 type: number + company_id: + example: 1 + type: integer id: example: 1 type: integer @@ -1655,60 +1984,36 @@ definitions: id: type: string type: object - domain.UpcomingEvent: + domain.UnifiedGame: properties: - away_kit_image: - description: Kit or image for away team (optional) + bets: + items: + type: number + type: array + category: type: string - away_team: - description: Away team name (can be empty/null) + deviceType: type: string - away_team_id: - description: Away team ID (can be empty/null) - type: integer - home_kit_image: - description: Kit or image for home team (optional) + gameId: type: string - home_team: - description: Home team name (if available) - type: string - home_team_id: - description: Home team ID - type: integer - id: - description: Event ID - type: string - is_active: - description: Whether the event is featured or not + hasDemo: type: boolean - is_featured: - description: Whether the event is featured or not + hasFreeBets: type: boolean - league_cc: - description: League country code + name: type: string - league_id: - description: League ID - type: integer - league_name: - description: League name + provider: type: string - match_name: - description: Match or event name - type: string - source: - description: bet api provider (bet365, betfair) - type: string - sport_id: - description: Sport ID - type: integer - start_time: - description: Converted from "time" field in UNIX format + providerId: type: string + rtp: + type: number status: - allOf: - - $ref: '#/definitions/domain.EventStatus' - description: Match Status for event + type: integer + thumbnail: + type: string + volatility: + type: string type: object domain.UpdateCompanyReq: properties: @@ -1731,6 +2036,27 @@ definitions: example: true type: boolean type: object + domain.ValidInt: + properties: + valid: + type: boolean + value: + type: integer + type: object + domain.ValidInt32: + properties: + valid: + type: boolean + value: + type: integer + type: object + domain.ValidString: + properties: + valid: + type: boolean + value: + type: string + type: object domain.VerifyDirectDepositRequest: properties: deposit_id: @@ -2194,7 +2520,7 @@ definitions: properties: events: items: - $ref: '#/definitions/domain.UpcomingEvent' + $ref: '#/definitions/domain.EventWithSettingsRes' type: array league_cc: type: string @@ -2512,6 +2838,1028 @@ info: title: FortuneBet API version: 1.0.1 paths: + /account: + post: + consumes: + - application/json + description: Callback endpoint for Atlas game server to fetch player balance + parameters: + - description: Get user data input + in: body + name: request + required: true + schema: + $ref: '#/definitions/domain.AtlasGetUserDataRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.AtlasGetUserDataResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Atlas Get User Data callback + tags: + - Virtual Games - Atlas + /api/v1/{tenant_slug}/admin-login: + post: + consumes: + - application/json + description: Login customer + parameters: + - description: Login admin + in: body + name: login + required: true + schema: + $ref: '#/definitions/handlers.loginAdminReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.loginAdminRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Login customer + tags: + - auth + /api/v1/{tenant_slug}/customer-login: + post: + consumes: + - application/json + description: Login customer + parameters: + - description: Login customer + in: body + name: login + required: true + schema: + $ref: '#/definitions/handlers.loginCustomerReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.loginCustomerRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Login customer + tags: + - auth + /api/v1/{tenant_slug}/events: + get: + consumes: + - application/json + description: Retrieve all upcoming events settings from the database + parameters: + - description: Page number + in: query + name: page + type: integer + - description: Page size + in: query + name: page_size + type: integer + - description: League ID Filter + in: query + name: league_id + type: string + - description: Sport ID Filter + in: query + name: sport_id + type: string + - description: Country Code Filter + in: query + name: cc + type: string + - description: Start Time + in: query + name: first_start_time + type: string + - description: End Time + in: query + name: last_start_time + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BaseEvent' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve all upcoming events with settings + tags: + - prematch + /api/v1/{tenant_slug}/events/{id}/settings: + put: + consumes: + - application/json + description: Update the event settings + parameters: + - description: Event ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: update the event settings + tags: + - event + /api/v1/{tenant_slug}/leagues: + get: + consumes: + - application/json + description: Gets all leagues + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BaseLeague' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all leagues + tags: + - leagues + /api/v1/{tenant_slug}/leagues/{id}/featured: + put: + consumes: + - application/json + description: Set the league to featured/un-featured + parameters: + - description: League ID + in: path + name: id + required: true + type: integer + - description: League Featured Request + in: body + name: active + required: true + schema: + $ref: '#/definitions/handlers.SetLeagueAsFeatured' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Set the league to featured/un-featured + tags: + - leagues + /api/v1/{tenant_slug}/leagues/{id}/set-active: + put: + consumes: + - application/json + description: Set the league to active + parameters: + - description: League ID + in: path + name: id + required: true + type: integer + - description: League Active Request + in: body + name: active + required: true + schema: + $ref: '#/definitions/handlers.SetLeagueActiveReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Set the league to active + tags: + - leagues + /api/v1/{tenant_slug}/odds: + get: + consumes: + - application/json + description: Retrieve all odds from the database + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.OddMarketFilter' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve all odds + tags: + - prematch + /api/v1/{tenant_slug}/odds/upcoming/{upcoming_id}: + get: + consumes: + - application/json + description: Retrieve prematch odds by upcoming event ID (FI from Bet365) with + optional pagination + parameters: + - description: Upcoming Event ID (FI) + in: path + name: upcoming_id + required: true + type: string + - description: 'Number of results to return (default: 10)' + in: query + name: limit + type: integer + - description: 'Number of results to skip (default: 0)' + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.OddMarketFilter' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve prematch odds by upcoming ID (FI) + tags: + - prematch + /api/v1/{tenant_slug}/odds/upcoming/{upcoming_id}/market/{market_id}: + get: + consumes: + - application/json + description: Retrieve raw odds records using a Market ID + parameters: + - description: Upcoming ID + in: path + name: upcoming_id + required: true + type: string + - description: Market ID + in: path + name: market_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.RawOddsByMarketID' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve raw odds by Market ID + tags: + - prematch + /api/v1/{tenant_slug}/sport/bet: + get: + consumes: + - application/json + description: Gets all the bets + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BetRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets all bets + tags: + - bet + post: + consumes: + - application/json + description: Creates a bet + parameters: + - description: Creates bet + in: body + name: createBet + required: true + schema: + $ref: '#/definitions/domain.CreateBetReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a bet + tags: + - bet + /api/v1/{tenant_slug}/sport/bet/{id}: + delete: + consumes: + - application/json + description: Deletes bet by id + parameters: + - description: Bet ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Deletes bet by id + tags: + - bet + get: + consumes: + - application/json + description: Gets a single bet by id + parameters: + - description: Bet ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets bet by id + tags: + - bet + patch: + consumes: + - application/json + description: Updates the cashed out field + parameters: + - description: Bet ID + in: path + name: id + required: true + type: integer + - description: Updates Cashed Out + in: body + name: updateCashOut + required: true + schema: + $ref: '#/definitions/handlers.UpdateCashOutReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Updates the cashed out field + tags: + - bet + /api/v1/{tenant_slug}/sport/bet/fastcode: + post: + consumes: + - application/json + description: Creates a bet with fast code + parameters: + - description: Creates bet + in: body + name: createBetWithFastCode + required: true + schema: + $ref: '#/definitions/domain.CreateBetWithFastCodeReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a bet with fast code + tags: + - bet + /api/v1/{tenant_slug}/sport/bet/fastcode/{fast_code}: + get: + consumes: + - application/json + description: Gets a single bet by fast_code + parameters: + - description: Bet ID + in: path + name: fast_code + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets bet by fast_code + tags: + - bet + /api/v1/{tenant_slug}/sport/random/bet: + post: + consumes: + - application/json + description: Generate a random bet + parameters: + - description: Create Random bet + in: body + name: createBet + required: true + schema: + $ref: '#/definitions/domain.RandomBetReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BetRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Generate a random bet + tags: + - bet + /api/v1/{tenant_slug}/ticket: + get: + consumes: + - application/json + description: Retrieve all tickets + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.TicketRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get all tickets + tags: + - ticket + post: + consumes: + - application/json + description: Creates a temporary ticket + parameters: + - description: Creates ticket + in: body + name: createTicket + required: true + schema: + $ref: '#/definitions/domain.CreateTicketReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.CreateTicketRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Create a temporary ticket + tags: + - ticket + /api/v1/{tenant_slug}/ticket/{id}: + get: + consumes: + - application/json + description: Retrieve ticket details by ticket ID + parameters: + - description: Ticket ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.TicketRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Get ticket by ID + tags: + - ticket + /api/v1/{tenant_slug}/top-leagues: + get: + consumes: + - application/json + description: Retrieve all top leagues + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/handlers.TopLeague' + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve all top leagues + tags: + - prematch + /api/v1/{tenant_slug}/user/admin-profile: + get: + consumes: + - application/json + description: Get user profile + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.AdminProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Get user profile + tags: + - user + /api/v1/{tenant_slug}/user/bets: + get: + consumes: + - application/json + description: Gets user bets + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/domain.BetRes' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Gets user bets + tags: + - user + /api/v1/{tenant_slug}/user/checkPhoneEmailExist: + post: + consumes: + - application/json + description: Check if phone number or email exist + parameters: + - description: Check phone number or email exist + in: body + name: checkPhoneEmailExist + required: true + schema: + $ref: '#/definitions/handlers.CheckPhoneEmailExistReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.CheckPhoneEmailExistRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Check if phone number or email exist + tags: + - user + /api/v1/{tenant_slug}/user/customer-profile: + get: + consumes: + - application/json + description: Get user profile + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.CustomerProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Get user profile + tags: + - user + /api/v1/{tenant_slug}/user/register: + post: + consumes: + - application/json + description: Register user + parameters: + - description: Register user + in: body + name: registerUser + required: true + schema: + $ref: '#/definitions/handlers.RegisterUserReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Register user + tags: + - user + /api/v1/{tenant_slug}/user/resetPassword: + post: + consumes: + - application/json + description: Reset password + parameters: + - description: Reset password + in: body + name: resetPassword + required: true + schema: + $ref: '#/definitions/handlers.ResetPasswordReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Reset password + tags: + - user + /api/v1/{tenant_slug}/user/search: + post: + consumes: + - application/json + description: Search for user using name or phone + parameters: + - description: Search for using his name or phone + in: body + name: searchUserByNameOrPhone + required: true + schema: + $ref: '#/definitions/handlers.SearchUserByNameOrPhoneReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.UserProfileRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Search for user using name or phone + tags: + - user + /api/v1/{tenant_slug}/user/sendRegisterCode: + post: + consumes: + - application/json + description: Send register code + parameters: + - description: Send register code + in: body + name: registerCode + required: true + schema: + $ref: '#/definitions/handlers.RegisterCodeReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Send register code + tags: + - user + /api/v1/{tenant_slug}/user/sendResetCode: + post: + consumes: + - application/json + description: Send reset code + parameters: + - description: Send reset code + in: body + name: resetCode + required: true + schema: + $ref: '#/definitions/handlers.ResetCodeReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.APIResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Send reset code + tags: + - user + /api/v1/{tenant_slug}/user/wallet: + get: + consumes: + - application/json + description: Retrieve customer wallet details + parameters: + - description: Company ID + in: header + name: company_id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handlers.CustomerWalletRes' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + security: + - Bearer: [] + summary: Get customer wallet + tags: + - wallet + /api/v1/{tenant_slug}events/{id}: + get: + consumes: + - application/json + description: Retrieve an upcoming event by ID + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.BaseEvent' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.APIResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.APIResponse' + summary: Retrieve an upcoming by ID + tags: + - prematch /api/v1/admin: get: consumes: @@ -2955,74 +4303,78 @@ paths: summary: Verify Arifpay Transaction tags: - Arifpay - /api/v1/auth/admin-login: + /api/v1/atlas/freespin: post: consumes: - application/json - description: Login customer + description: Sends a request to Atlas to create free spins/bets for a given + player parameters: - - description: Login admin + - description: Free spin input in: body - name: login + name: request required: true schema: - $ref: '#/definitions/handlers.loginAdminReq' + $ref: '#/definitions/domain.FreeSpinRequest' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/handlers.loginAdminRes' + allOf: + - $ref: '#/definitions/domain.Response' + - properties: + data: + $ref: '#/definitions/domain.FreeSpinResponse' + type: object "400": description: Bad Request schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Login customer + $ref: '#/definitions/domain.ErrorResponse' + summary: Create free spins for a player tags: - - auth - /api/v1/auth/customer-login: + - Virtual Games - Atlas + /api/v1/atlas/init-game: post: consumes: - application/json - description: Login customer + description: Initializes a game session for the given player using Atlas virtual + game provider parameters: - - description: Login customer + - description: Start game input in: body - name: login + name: request required: true schema: - $ref: '#/definitions/handlers.loginCustomerReq' + $ref: '#/definitions/domain.AtlasGameInitRequest' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/handlers.loginCustomerRes' + allOf: + - $ref: '#/definitions/domain.Response' + - properties: + data: + $ref: '#/definitions/domain.AtlasGameInitResponse' + type: object "400": description: Bad Request schema: - $ref: '#/definitions/response.APIResponse' - "401": - description: Unauthorized + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Login customer + $ref: '#/definitions/domain.ErrorResponse' + summary: Start an Atlas virtual game session tags: - - auth + - Virtual Games - Atlas /api/v1/auth/logout: post: consumes: @@ -4411,7 +5763,7 @@ paths: description: OK schema: items: - $ref: '#/definitions/domain.UpcomingEvent' + $ref: '#/definitions/domain.BaseEvent' type: array "500": description: Internal Server Error @@ -4465,7 +5817,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/domain.UpcomingEvent' + $ref: '#/definitions/domain.BaseEvent' "400": description: Bad Request schema: @@ -4477,35 +5829,6 @@ paths: summary: Retrieve an upcoming by ID tags: - prematch - /api/v1/events/{id}/flag: - put: - consumes: - - application/json - description: Update the event featured - parameters: - - description: Event ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: update the event featured - tags: - - event /api/v1/issues: get: description: Admin endpoint to list all reported issues with pagination @@ -4666,7 +5989,7 @@ paths: description: OK schema: items: - $ref: '#/definitions/domain.League' + $ref: '#/definitions/domain.BaseLeague' type: array "400": description: Bad Request @@ -4679,76 +6002,6 @@ paths: summary: Gets all leagues tags: - leagues - /api/v1/leagues/{id}/featured: - put: - consumes: - - application/json - description: Set the league to featured/un-featured - parameters: - - description: League ID - in: path - name: id - required: true - type: integer - - description: League Featured Request - in: body - name: active - required: true - schema: - $ref: '#/definitions/handlers.SetLeagueAsFeatured' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Set the league to featured/un-featured - tags: - - leagues - /api/v1/leagues/{id}/set-active: - put: - consumes: - - application/json - description: Set the league to active - parameters: - - description: League ID - in: path - name: id - required: true - type: integer - - description: League Active Request - in: body - name: active - required: true - schema: - $ref: '#/definitions/handlers.SetLeagueActiveReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Set the league to active - tags: - - leagues /api/v1/logs: get: description: Fetches application logs from MongoDB with pagination, level filtering, @@ -4961,7 +6214,7 @@ paths: get: consumes: - application/json - description: Retrieve all prematch odds from the database + description: Retrieve all odds from the database produces: - application/json responses: @@ -4969,13 +6222,13 @@ paths: description: OK schema: items: - $ref: '#/definitions/domain.Odd' + $ref: '#/definitions/domain.OddMarketFilter' type: array "500": description: Internal Server Error schema: $ref: '#/definitions/response.APIResponse' - summary: Retrieve all prematch odds + summary: Retrieve all odds tags: - prematch /api/v1/odds/upcoming/{upcoming_id}: @@ -5005,7 +6258,7 @@ paths: description: OK schema: items: - $ref: '#/definitions/domain.Odd' + $ref: '#/definitions/domain.OddMarketWithEventFilter' type: array "400": description: Bad Request @@ -5084,6 +6337,54 @@ paths: summary: Create a operation tags: - branch + /api/v1/orchestrator/virtual-games: + get: + consumes: + - application/json + description: Returns all virtual games with optional filters (category, search, + pagination) + parameters: + - description: Filter by category + in: query + name: category + type: string + - description: Search by game name + in: query + name: search + type: string + - description: Pagination limit + in: query + name: limit + type: integer + - description: Pagination offset + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/domain.Response' + - properties: + data: + items: + $ref: '#/definitions/domain.UnifiedGame' + type: array + type: object + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: List all virtual games + tags: + - VirtualGames - Orchestration /api/v1/referral/settings: get: consumes: @@ -5880,240 +7181,40 @@ paths: summary: Gets shop bet by transaction id tags: - transaction - /api/v1/sport/bet: - get: - consumes: - - application/json - description: Gets all the bets - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.BetRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets all bets - tags: - - bet + /api/v1/super-login: post: consumes: - application/json - description: Creates a bet + description: Login super-admin parameters: - - description: Creates bet + - description: Login super-admin in: body - name: createBet + name: login required: true schema: - $ref: '#/definitions/domain.CreateBetReq' + $ref: '#/definitions/handlers.loginAdminReq' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/domain.BetRes' + $ref: '#/definitions/handlers.loginAdminRes' "400": description: Bad Request schema: $ref: '#/definitions/response.APIResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.APIResponse' "500": description: Internal Server Error schema: $ref: '#/definitions/response.APIResponse' - summary: Create a bet + summary: Login super-admin tags: - - bet - /api/v1/sport/bet/{id}: - delete: - consumes: - - application/json - description: Deletes bet by id - parameters: - - description: Bet ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Deletes bet by id - tags: - - bet - get: - consumes: - - application/json - description: Gets a single bet by id - parameters: - - description: Bet ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets bet by id - tags: - - bet - patch: - consumes: - - application/json - description: Updates the cashed out field - parameters: - - description: Bet ID - in: path - name: id - required: true - type: integer - - description: Updates Cashed Out - in: body - name: updateCashOut - required: true - schema: - $ref: '#/definitions/handlers.UpdateCashOutReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Updates the cashed out field - tags: - - bet - /api/v1/sport/bet/fastcode: - post: - consumes: - - application/json - description: Creates a bet with fast code - parameters: - - description: Creates bet - in: body - name: createBetWithFastCode - required: true - schema: - $ref: '#/definitions/domain.CreateBetWithFastCodeReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a bet with fast code - tags: - - bet - /api/v1/sport/bet/fastcode/{fast_code}: - get: - consumes: - - application/json - description: Gets a single bet by fast_code - parameters: - - description: Bet ID - in: path - name: fast_code - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets bet by fast_code - tags: - - bet - /api/v1/sport/random/bet: - post: - consumes: - - application/json - description: Generate a random bet - parameters: - - description: Create Random bet - in: body - name: createBet - required: true - schema: - $ref: '#/definitions/domain.RandomBetReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.BetRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Generate a random bet - tags: - - bet + - auth /api/v1/supportedOperation: get: consumes: @@ -6228,110 +7329,6 @@ paths: summary: Create Telebirr Payment Session tags: - Telebirr - /api/v1/ticket: - get: - consumes: - - application/json - description: Retrieve all tickets - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.TicketRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get all tickets - tags: - - ticket - post: - consumes: - - application/json - description: Creates a temporary ticket - parameters: - - description: Creates ticket - in: body - name: createTicket - required: true - schema: - $ref: '#/definitions/domain.CreateTicketReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.CreateTicketRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Create a temporary ticket - tags: - - ticket - /api/v1/ticket/{id}: - get: - consumes: - - application/json - description: Retrieve ticket details by ticket ID - parameters: - - description: Ticket ID - in: path - name: id - required: true - type: integer - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/domain.TicketRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Get ticket by ID - tags: - - ticket - /api/v1/top-leagues: - get: - consumes: - - application/json - description: Retrieve all top leagues - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/handlers.TopLeague' - type: array - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Retrieve all top leagues - tags: - - prematch /api/v1/transfer/refill/:id: post: consumes: @@ -6422,111 +7419,6 @@ paths: summary: Get transfer by wallet tags: - transfer - /api/v1/user/admin-profile: - get: - consumes: - - application/json - description: Get user profile - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.AdminProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Get user profile - tags: - - user - /api/v1/user/bets: - get: - consumes: - - application/json - description: Gets user bets - produces: - - application/json - responses: - "200": - description: OK - schema: - items: - $ref: '#/definitions/domain.BetRes' - type: array - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Gets user bets - tags: - - user - /api/v1/user/checkPhoneEmailExist: - post: - consumes: - - application/json - description: Check if phone number or email exist - parameters: - - description: Check phone number or email exist - in: body - name: checkPhoneEmailExist - required: true - schema: - $ref: '#/definitions/handlers.CheckPhoneEmailExistReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.CheckPhoneEmailExistRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Check if phone number or email exist - tags: - - user - /api/v1/user/customer-profile: - get: - consumes: - - application/json - description: Get user profile - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.CustomerProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Get user profile - tags: - - user /api/v1/user/delete/{id}: delete: consumes: @@ -6556,156 +7448,6 @@ paths: summary: Delete user by ID tags: - user - /api/v1/user/register: - post: - consumes: - - application/json - description: Register user - parameters: - - description: Register user - in: body - name: registerUser - required: true - schema: - $ref: '#/definitions/handlers.RegisterUserReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Register user - tags: - - user - /api/v1/user/resetPassword: - post: - consumes: - - application/json - description: Reset password - parameters: - - description: Reset password - in: body - name: resetPassword - required: true - schema: - $ref: '#/definitions/handlers.ResetPasswordReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Reset password - tags: - - user - /api/v1/user/search: - post: - consumes: - - application/json - description: Search for user using name or phone - parameters: - - description: Search for using his name or phone - in: body - name: searchUserByNameOrPhone - required: true - schema: - $ref: '#/definitions/handlers.SearchUserByNameOrPhoneReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/handlers.UserProfileRes' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Search for user using name or phone - tags: - - user - /api/v1/user/sendRegisterCode: - post: - consumes: - - application/json - description: Send register code - parameters: - - description: Send register code - in: body - name: registerCode - required: true - schema: - $ref: '#/definitions/handlers.RegisterCodeReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Send register code - tags: - - user - /api/v1/user/sendResetCode: - post: - consumes: - - application/json - description: Send reset code - parameters: - - description: Send reset code - in: body - name: resetCode - required: true - schema: - $ref: '#/definitions/handlers.ResetCodeReq' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/response.APIResponse' - "400": - description: Bad Request - schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/response.APIResponse' - summary: Send reset code - tags: - - user /api/v1/user/single/{id}: get: consumes: @@ -6769,37 +7511,43 @@ paths: summary: Suspend or unsuspend a user tags: - user - /api/v1/user/wallet: + /api/v1/veli/credit-balances: get: consumes: - application/json - description: Retrieve customer wallet details + description: Fetches current credit balances per currency for the specified + brand parameters: - - description: Company ID - in: header - name: company_id + - description: Brand ID + in: query + name: brandId required: true - type: integer + type: string produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/handlers.CustomerWalletRes' + allOf: + - $ref: '#/definitions/domain.Response' + - properties: + data: + items: + $ref: '#/definitions/domain.CreditBalance' + type: array + type: object "400": description: Bad Request schema: - $ref: '#/definitions/response.APIResponse' - "500": - description: Internal Server Error + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway schema: - $ref: '#/definitions/response.APIResponse' - security: - - Bearer: [] - summary: Get customer wallet + $ref: '#/definitions/domain.ErrorResponse' + summary: Get VeliGames credit balances for a brand tags: - - wallet + - Virtual Games - VeliGames /api/v1/veli/games-list: post: consumes: @@ -7335,6 +8083,96 @@ paths: summary: Handle win callback (Veli or PopOK) tags: - Wins + /betwin: + post: + consumes: + - application/json + description: Processes a Bet and Win request from Atlas provider + parameters: + - description: Atlas BetWin input + in: body + name: request + required: true + schema: + $ref: '#/definitions/domain.AtlasBetWinRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.AtlasBetWinResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Atlas BetWin callback + tags: + - Virtual Games - Atlas + /freespin: + post: + consumes: + - application/json + description: Handles the result of a free spin/bet from the game server + parameters: + - description: Free spin result input + in: body + name: request + required: true + schema: + $ref: '#/definitions/domain.FreeSpinResultRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.FreeSpinResultResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Free Spin/Bet result callback + tags: + - Virtual Games - Atlas + /jackpot: + post: + consumes: + - application/json + description: Handles the jackpot result from the game server + parameters: + - description: Jackpot result input + in: body + name: request + required: true + schema: + $ref: '#/definitions/domain.JackpotRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.JackpotResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Jackpot result callback + tags: + - Virtual Games - Atlas /popok/games: get: consumes: @@ -7387,6 +8225,66 @@ paths: summary: Recommend virtual games tags: - Virtual Games - PopOK + /result: + post: + consumes: + - application/json + description: Processes a round result from Atlas or other providers + parameters: + - description: Round result input + in: body + name: request + required: true + schema: + $ref: '#/definitions/domain.RoundResultRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.RoundResultResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Atlas Round Result callback + tags: + - Virtual Games - Atlas + /rollback: + post: + consumes: + - application/json + description: Processes a rollback request from Atlas or other providers + parameters: + - description: Rollback request input + in: body + name: request + required: true + schema: + $ref: '#/definitions/domain.RollbackRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/domain.RollbackResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/domain.ErrorResponse' + "502": + description: Bad Gateway + schema: + $ref: '#/definitions/domain.ErrorResponse' + summary: Atlas Rollback callback + tags: + - Virtual Games - Atlas /virtual-game/callback: post: consumes: diff --git a/internal/config/config.go b/internal/config/config.go index 926d4fe..3288398 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -59,6 +59,14 @@ type VeliConfig struct { Enabled bool `mapstructure:"Enabled"` } +type AtlasConfig struct { + BaseURL string `mapstructure:"ATLAS_BASE_URL"` + SecretKey string `mapstructure:"ATLAS_SECRET_KEY"` + OperatorID string `mapstructure:"ATLAS_OPERATOR_ID"` + CasinoID string `mapstructure:"ATLAS_BRAND_ID"` + PartnerID string `mapstructure:"ATLAS_PARTNER_ID"` +} + type ARIFPAYConfig struct { APIKey string `mapstructure:"ARIFPAY_API_KEY"` BaseURL string `mapstructure:"ARIFPAY_BASE_URL"` @@ -126,6 +134,7 @@ type Config struct { Bet365Token string PopOK domain.PopOKConfig AleaPlay AleaPlayConfig `mapstructure:"alea_play"` + Atlas AtlasConfig `mapstructure:"atlas"` VeliGames VeliConfig `mapstructure:"veli_games"` ARIFPAY ARIFPAYConfig `mapstructure:"arifpay_config"` SANTIMPAY SANTIMPAYConfig `mapstructure:"santimpay_config"` diff --git a/internal/domain/atlas.go b/internal/domain/atlas.go new file mode 100644 index 0000000..66f8cb7 --- /dev/null +++ b/internal/domain/atlas.go @@ -0,0 +1,151 @@ +package domain + +import "errors" + +type AtlasGameInitRequest struct { + Game string `json:"game"` + PlayerID string `json:"player_id"` + Language string `json:"language"` + Currency string `json:"currency"` +} + +type AtlasGameInitResponse struct { + URL string `json:"url"` +} + +type AtlasGetUserDataRequest struct { + Game string `json:"game"` + CasinoID string `json:"casino_id"` + PlayerID string `json:"player_id"` + SessionID string `json:"session_id"` + // timestamp and hash will also be included in the incoming JSON +} + +type AtlasGetUserDataResponse struct { + PlayerID string `json:"player_id"` + Balance float64 `json:"balance"` +} + +type AtlasBetRequest struct { + Game string `json:"game"` + CasinoID string `json:"casino_id"` + PlayerID string `json:"player_id"` + SessionID string `json:"session_id"` + Amount float64 `json:"amount"` + Currency string `json:"currency"` + RoundID int64 `json:"round_id"` + TransactionID string `json:"transaction_id"` + Details string `json:"details"` +} + +type AtlasBetResponse struct { + PlayerID string `json:"player_id"` + Balance float64 `json:"balance"` +} + +type AtlasBetWinRequest struct { + Game string `json:"game"` + CasinoID string `json:"casino_id"` + RoundID int64 `json:"round_id"` + PlayerID string `json:"player_id"` + SessionID string `json:"session_id"` + BetAmount float64 `json:"betAmount"` + WinAmount float64 `json:"winAmount"` + Currency string `json:"currency"` + TransactionID string `json:"transaction_id"` + Timestamp string `json:"timestamp"` + Hash string `json:"hash"` +} + +type AtlasBetWinResponse struct { + PlayerID string `json:"player_id"` + Balance float64 `json:"balance"` +} + +type RoundResultRequest struct { + Game string `json:"game"` + RoundID int64 `json:"round_id"` + CasinoID string `json:"casino_id"` + PlayerID string `json:"player_id"` + Amount float64 `json:"amount"` // win amount + Currency string `json:"currency"` + TransactionID string `json:"transaction_id"` // new transaction id + BetTransactionID string `json:"bet_transaction_id"` // from BET request + SessionID string `json:"session_id"` + Timestamp string `json:"timestamp"` + Hash string `json:"hash"` +} + +type RoundResultResponse struct { + Success bool `json:"success"` +} + +type RollbackRequest struct { + Game string `json:"game"` + RoundID int64 `json:"round_id"` + CasinoID string `json:"casino_id"` + PlayerID string `json:"player_id"` + BetTransactionID string `json:"bet_transaction_id"` + SessionID string `json:"session_id"` + Timestamp string `json:"timestamp"` + Hash string `json:"hash"` +} + +type RollbackResponse struct { + Success bool `json:"success"` +} + +type FreeSpinRequest struct { + CasinoID string `json:"casino_id"` + PlayerID string `json:"player_id"` + EndDate string `json:"end_date"` // "yyyy-mm-ddTHH:MM:SS+00:00" + FreeSpinsCount int `json:"freespins_count"` // count of free spins/bets + Timestamp string `json:"timestamp"` + Hash string `json:"hash"` +} + +type FreeSpinResponse struct { + Success bool `json:"success"` +} + +type FreeSpinResultRequest struct { + Game string `json:"game"` + RoundID int64 `json:"round_id"` + CasinoID string `json:"casino_id"` + PlayerID string `json:"player_id"` + Amount float64 `json:"amount"` // win amount + Currency string `json:"currency"` + TransactionID string `json:"transaction_id"` + SessionID string `json:"session_id"` + Timestamp string `json:"timestamp"` + Hash string `json:"hash"` +} + +type FreeSpinResultResponse struct { + Success bool `json:"success"` +} + +type JackpotRequest struct { + Game string `json:"game"` + CasinoID string `json:"casino_id"` + PlayerID string `json:"player_id"` + SessionID string `json:"session_id"` + Amount float64 `json:"amount"` // jackpot win + Currency string `json:"currency"` + RoundID int64 `json:"round_id"` + TransactionID string `json:"transaction_id"` + Details string `json:"details,omitempty"` + Timestamp string `json:"timestamp"` + Hash string `json:"hash"` +} + +type JackpotResponse struct { + Success bool `json:"success"` +} + +var ( + ErrPlayerNotFound = errors.New("PLAYER_NOT_FOUND") + ErrSessionExpired = errors.New("SESSION_EXPIRED") + ErrWalletsNotFound = errors.New("WALLETS_NOT_FOUND") + ErrDuplicateTransaction = errors.New("DUPLICATE_TRANSACTION") +) diff --git a/internal/domain/odds.go b/internal/domain/odds.go index fa30718..c56d320 100644 --- a/internal/domain/odds.go +++ b/internal/domain/odds.go @@ -61,14 +61,14 @@ type CreateOddMarketSettings struct { CustomRawOdds []map[string]interface{} } -// type RawOddsByMarketID struct { -// ID int64 `json:"id"` -// MarketName string `json:"market_name"` -// Handicap string `json:"handicap"` -// RawOdds []json.RawMessage `json:"raw_odds"` -// FetchedAt time.Time `json:"fetched_at"` -// ExpiresAt time.Time `json:"expires_at"` -// } +type RawOddsByMarketID struct { + ID int64 `json:"id"` + MarketName string `json:"market_name"` + Handicap string `json:"handicap"` + RawOdds []map[string]interface{} `json:"raw_odds"` + FetchedAt time.Time `json:"fetched_at"` + ExpiresAt time.Time `json:"expires_at"` +} type OddMarketFilter struct { Limit ValidInt32 diff --git a/internal/domain/veli_games.go b/internal/domain/veli_games.go index 3b86e83..2fad79a 100644 --- a/internal/domain/veli_games.go +++ b/internal/domain/veli_games.go @@ -136,7 +136,7 @@ type CancelRequest struct { CorrelationID string `json:"correlationId,omitempty"` ProviderID string `json:"providerId"` BrandID string `json:"brandId"` - IsAdjustment bool `json:"isAdjustment,omitempty"` + IsAdjustment bool `json:"isAdjustment,omitempty"` AdjustmentRefund *struct { Amount float64 `json:"amount"` Currency string `json:"currency"` @@ -254,3 +254,9 @@ type HugeWinItem struct { CreatedAt string `json:"createdAt"` Reason string `json:"reason"` } + +type CreditBalance struct { + Currency string `json:"currency"` + Balance float64 `json:"balance"` + Threshold float64 `json:"threshold"` +} diff --git a/internal/services/virtualGame/atlas/client.go b/internal/services/virtualGame/atlas/client.go new file mode 100644 index 0000000..0047d81 --- /dev/null +++ b/internal/services/virtualGame/atlas/client.go @@ -0,0 +1,89 @@ +package atlas + +import ( + "bytes" + "context" + "crypto/sha1" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/config" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" +) + +type Client struct { + http *http.Client + BaseURL string + PrivateKey string + CasinoID string + PartnerID string + walletSvc *wallet.Service +} + +func NewClient(cfg *config.Config, walletSvc *wallet.Service) *Client { + return &Client{ + http: &http.Client{Timeout: 10 * time.Second}, + BaseURL: cfg.Atlas.BaseURL, + PrivateKey: cfg.Atlas.SecretKey, // PRIVATE_KEY from Atlas + CasinoID: cfg.Atlas.CasinoID, // provided by Atlas + PartnerID: cfg.Atlas.PartnerID, // aggregator/casino partner_id + walletSvc: walletSvc, + } +} + +// Generate timestamp in ms +func nowTimestamp() string { + return fmt.Sprintf("%d", time.Now().UnixMilli()) +} + +// Signature generator: sha1 hex of (REQUEST_BODY + PRIVATE_KEY + timestamp) +func (c *Client) generateHash(body []byte, timestamp string) string { + plain := string(body) + c.PrivateKey + timestamp + h := sha1.New() + h.Write([]byte(plain)) + return hex.EncodeToString(h.Sum(nil)) +} + +// POST helper +func (c *Client) post(ctx context.Context, path string, body map[string]any, result any) error { + // Add timestamp first + timestamp := nowTimestamp() + body["timestamp"] = timestamp + + // Marshal without hash first + tmp, _ := json.Marshal(body) + + // Generate hash using original body + hash := c.generateHash(tmp, timestamp) + body["hash"] = hash + + // Marshal final body + data, _ := json.Marshal(body) + + req, _ := http.NewRequestWithContext(ctx, "POST", c.BaseURL+path, bytes.NewReader(data)) + req.Header.Set("Content-Type", "text/javascript") + + // Debug + fmt.Println("Request URL:", c.BaseURL+path) + fmt.Println("Request Body:", string(data)) + + // Send request + res, err := c.http.Do(req) + if err != nil { + return err + } + defer res.Body.Close() + + b, _ := io.ReadAll(res.Body) + if res.StatusCode >= 400 { + return fmt.Errorf("error: %s", string(b)) + } + if result != nil { + return json.Unmarshal(b, result) + } + return nil +} diff --git a/internal/services/virtualGame/atlas/port.go b/internal/services/virtualGame/atlas/port.go new file mode 100644 index 0000000..832c828 --- /dev/null +++ b/internal/services/virtualGame/atlas/port.go @@ -0,0 +1,20 @@ +// services/veli/service.go +package atlas + +import ( + "context" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +) + +type AtlasVirtualGameService interface { + InitGame(ctx context.Context, req domain.AtlasGameInitRequest) (*domain.AtlasGameInitResponse, error) + GetUserData(ctx context.Context, req domain.AtlasGetUserDataRequest) (*domain.AtlasGetUserDataResponse, error) + ProcessBet(ctx context.Context, req domain.AtlasBetRequest) (*domain.AtlasBetResponse, error) + ProcessBetWin(ctx context.Context, req domain.AtlasBetWinRequest) (*domain.AtlasBetWinResponse, error) + ProcessRoundResult(ctx context.Context, req domain.RoundResultRequest) (*domain.RoundResultResponse, error) + ProcessRollBack(ctx context.Context, req domain.RollbackRequest) (*domain.RollbackResponse, error) + CreateFreeSpin(ctx context.Context, req domain.FreeSpinRequest) (*domain.FreeSpinResponse, error) + ProcessFreeSpinResult(ctx context.Context, req domain.FreeSpinResultRequest) (*domain.FreeSpinResultResponse, error) + ProcessJackPot(ctx context.Context, req domain.JackpotRequest) (*domain.JackpotResponse, error) +} diff --git a/internal/services/virtualGame/atlas/service.go b/internal/services/virtualGame/atlas/service.go new file mode 100644 index 0000000..36c2c29 --- /dev/null +++ b/internal/services/virtualGame/atlas/service.go @@ -0,0 +1,323 @@ +package atlas + +import ( + "context" + "errors" + "fmt" + "strconv" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/config" + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" + virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" +) + +type Service struct { + virtualGameSvc virtualgameservice.VirtualGameService + repo repository.VirtualGameRepository + client *Client + walletSvc *wallet.Service + transfetStore wallet.TransferStore + cfg *config.Config +} + +func New(virtualGameSvc virtualgameservice.VirtualGameService, repo repository.VirtualGameRepository, client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service { + return &Service{ + virtualGameSvc: virtualGameSvc, + repo: repo, + client: client, + walletSvc: walletSvc, + transfetStore: transferStore, + cfg: cfg, + } +} + +func (s *Service) InitGame(ctx context.Context, req domain.AtlasGameInitRequest) (*domain.AtlasGameInitResponse, error) { + + body := map[string]any{ + "game": req.Game, + "partner_id": s.client.PartnerID, + "casino_id": s.client.CasinoID, + "language": req.Language, + "currency": req.Currency, + "player_id": req.PlayerID, + } + + // 3. Call the Atlas client + var res domain.AtlasGameInitResponse + if err := s.client.post(ctx, "/init", body, &res); err != nil { + return nil, fmt.Errorf("failed to initialize game: %w", err) + } + + return &res, nil +} + +func (s *Service) GetUserData(ctx context.Context, req domain.AtlasGetUserDataRequest) (*domain.AtlasGetUserDataResponse, error) { + // 1. Validate casino_id and hash if needed + if req.CasinoID != s.client.CasinoID { + return nil, fmt.Errorf("invalid casino_id") + } + // 2. Fetch player from DB + playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid playerID: %w", err) + } + wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt) + if err != nil { + return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) + } + + // 4. Build response + res := &domain.AtlasGetUserDataResponse{ + PlayerID: req.PlayerID, + Balance: float64(wallet.RegularBalance), + } + + return res, nil +} + +func (s *Service) ProcessBet(ctx context.Context, req domain.AtlasBetRequest) (*domain.AtlasBetResponse, error) { + if req.CasinoID != s.client.CasinoID { + return nil, fmt.Errorf("invalid casino_id") + } + + playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid playerID: %w", err) + } + + wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt) + if err != nil { + return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) + } + // if player == nil { + // return nil, ErrPlayerNotFound + // } + + // 3. Check for duplicate transaction + // exists, err := s.repo.TransactionExists(ctx, req.TransactionID) + // if err != nil { + // return nil, fmt.Errorf("failed to check transaction: %w", err) + // } + // if exists { + // return nil, ErrDuplicateTransaction + // } + + // // 4. Get current balance + // balance, err := s.walletSvc.GetBalance(ctx, req.PlayerID) + // if err != nil { + // return nil, fmt.Errorf("failed to fetch wallet balance: %w", err) + // } + + // 5. Ensure sufficient balance + if float64(wallet.RegularBalance) < req.Amount { + return nil, domain.ErrInsufficientBalance + } + + // 6. Deduct amount from wallet (record transaction) + _, err = s.walletSvc.DeductFromWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), "") + if err != nil { + return nil, fmt.Errorf("failed to debit wallet: %w", err) + } + + // 7. Save transaction record to DB (optional but recommended) + // if err := s.repo.SaveBetTransaction(ctx, req); err != nil { + // // log warning but don’t fail response to Atlas + // fmt.Printf("warning: failed to save bet transaction: %v\n", err) + // } + + // 8. Build response + res := &domain.AtlasBetResponse{ + PlayerID: req.PlayerID, + Balance: float64(wallet.RegularBalance) - req.Amount, + } + + return res, nil +} + +func (s *Service) ProcessBetWin(ctx context.Context, req domain.AtlasBetWinRequest) (*domain.AtlasBetWinResponse, error) { + if req.CasinoID != s.client.CasinoID { + return nil, fmt.Errorf("invalid casino_id") + } + + playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid playerID: %w", err) + } + + wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt) + if err != nil { + return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) + } + + // 5. Ensure sufficient balance + if float64(wallet.RegularBalance) < req.BetAmount { + return nil, domain.ErrInsufficientBalance + } + + // 6. Deduct amount from wallet (record transaction) + _, err = s.walletSvc.DeductFromWallet(ctx, wallet.ID, domain.Currency(req.BetAmount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), "") + if err != nil { + return nil, fmt.Errorf("failed to debit wallet: %w", err) + } + + if req.WinAmount > 0 { + _, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.WinAmount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") + if err != nil { + return nil, fmt.Errorf("failed to credit wallet: %w", err) + } + } + + // 8. Build response + res := &domain.AtlasBetWinResponse{ + PlayerID: req.PlayerID, + Balance: float64(wallet.RegularBalance) - req.BetAmount + req.WinAmount, + } + + return res, nil +} + +func (s *Service) ProcessRoundResult(ctx context.Context, req domain.RoundResultRequest) (*domain.RoundResultResponse, error) { + if req.PlayerID == "" || req.TransactionID == "" { + return nil, errors.New("missing player_id or transaction_id") + } + + // Credit player with win amount if > 0 + if req.Amount > 0 { + // This will credit player's balance + playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid playerID: %w", err) + } + + wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt) + if err != nil { + return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) + } + + _, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") + if err != nil { + return nil, fmt.Errorf("failed to credit wallet: %w", err) + } + + } + + return &domain.RoundResultResponse{Success: true}, nil +} + +func (s *Service) ProcessRollBack(ctx context.Context, req domain.RollbackRequest) (*domain.RollbackResponse, error) { + if req.PlayerID == "" || req.BetTransactionID == "" { + return nil, errors.New("missing player_id or transaction_id") + } + + // Credit player with win amount if > 0 + // This will credit player's balance + playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid playerID: %w", err) + } + + wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt) + if err != nil { + return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) + } + + transfer, err := s.transfetStore.GetTransferByReference(ctx, req.BetTransactionID) + if err != nil { + return nil, fmt.Errorf("failed to fetch transfer for reference %s: %w", req.BetTransactionID, err) + } + + _, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(transfer.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") + if err != nil { + return nil, fmt.Errorf("failed to credit wallet: %w", err) + } + + err = s.transfetStore.UpdateTransferStatus(ctx, transfer.ID, string(domain.STATUS_CANCELLED)) + if err != nil { + return nil, fmt.Errorf("failed to update transfer status: %w", err) + } + + err = s.transfetStore.UpdateTransferVerification(ctx, transfer.ID, true) + if err != nil { + return nil, fmt.Errorf("failed to update transfer verification: %w", err) + } + + return &domain.RollbackResponse{Success: true}, nil +} + +func (s *Service) CreateFreeSpin(ctx context.Context, req domain.FreeSpinRequest) (*domain.FreeSpinResponse, error) { + + body := map[string]any{ + "casino_id": s.client.CasinoID, + "freespins_count": req.FreeSpinsCount, + "end_date": req.EndDate, + "player_id": req.PlayerID, + } + + // 3. Call the Atlas client + var res domain.FreeSpinResponse + if err := s.client.post(ctx, "/freespin", body, &res); err != nil { + return nil, fmt.Errorf("failed to create free spin: %w", err) + } + + return &res, nil +} + +func (s *Service) ProcessFreeSpinResult(ctx context.Context, req domain.FreeSpinResultRequest) (*domain.FreeSpinResultResponse, error) { + + if req.PlayerID == "" || req.TransactionID == "" { + return nil, errors.New("missing player_id or transaction_id") + } + + // Credit player with win amount if > 0 + if req.Amount > 0 { + // This will credit player's balance + playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid playerID: %w", err) + } + + wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt) + if err != nil { + return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) + } + + _, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") + if err != nil { + return nil, fmt.Errorf("failed to credit wallet: %w", err) + } + + } + + return &domain.FreeSpinResultResponse{Success: true}, nil +} + +func (s *Service) ProcessJackPot(ctx context.Context, req domain.JackpotRequest) (*domain.JackpotResponse, error) { + + if req.PlayerID == "" || req.TransactionID == "" { + return nil, errors.New("missing player_id or transaction_id") + } + + // Credit player with win amount if > 0 + if req.Amount > 0 { + // This will credit player's balance + playerIDInt, err := strconv.ParseInt(req.PlayerID, 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid playerID: %w", err) + } + + wallet, err := s.walletSvc.GetCustomerWallet(ctx, playerIDInt) + if err != nil { + return nil, fmt.Errorf("failed to fetch walllets for player %d: %w", playerIDInt, err) + } + + _, err = s.walletSvc.AddToWallet(ctx, wallet.ID, domain.Currency(req.Amount), domain.ValidInt64{}, domain.PaymentMethod(domain.DEPOSIT), domain.PaymentDetails{}, "") + if err != nil { + return nil, fmt.Errorf("failed to credit wallet: %w", err) + } + + } + + return &domain.JackpotResponse{Success: true}, nil +} diff --git a/internal/services/virtualGame/veli/port.go b/internal/services/virtualGame/veli/port.go index 1b56924..edbffe2 100644 --- a/internal/services/virtualGame/veli/port.go +++ b/internal/services/virtualGame/veli/port.go @@ -22,4 +22,5 @@ type VeliVirtualGameService interface { ProcessCancel(ctx context.Context, req domain.CancelRequest) (*domain.CancelResponse, error) GetGamingActivity(ctx context.Context, req domain.GamingActivityRequest) (*domain.GamingActivityResponse, error) GetHugeWins(ctx context.Context, req domain.HugeWinsRequest) (*domain.HugeWinsResponse, error) + GetCreditBalances(ctx context.Context, brandID string) ([]domain.CreditBalance, error) } diff --git a/internal/services/virtualGame/veli/service.go b/internal/services/virtualGame/veli/service.go index 2de2eb4..0bf78a7 100644 --- a/internal/services/virtualGame/veli/service.go +++ b/internal/services/virtualGame/veli/service.go @@ -22,23 +22,23 @@ var ( type Service struct { virtualGameSvc virtualgameservice.VirtualGameService - repo repository.VirtualGameRepository - client *Client - walletSvc *wallet.Service - transfetStore wallet.TransferStore - cfg *config.Config + repo repository.VirtualGameRepository + client *Client + walletSvc *wallet.Service + transfetStore wallet.TransferStore + cfg *config.Config } -func New(virtualGameSvc virtualgameservice.VirtualGameService,repo repository.VirtualGameRepository,client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service { +func New(virtualGameSvc virtualgameservice.VirtualGameService, repo repository.VirtualGameRepository, client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service { return &Service{ virtualGameSvc: virtualGameSvc, - repo: repo, - client: client, - walletSvc: walletSvc, - transfetStore: transferStore, - cfg: cfg, + repo: repo, + client: client, + walletSvc: walletSvc, + transfetStore: transferStore, + cfg: cfg, } -} +} func (s *Service) GetProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error) { // Always mirror request body fields into sigParams @@ -128,7 +128,6 @@ func (s *Service) StartGame(ctx context.Context, req domain.GameStartRequest) (* return &res, nil } - func (s *Service) StartDemoGame(ctx context.Context, req domain.DemoGameRequest) (*domain.GameStartResponse, error) { // 1. Check if provider is enabled in DB provider, err := s.repo.GetVirtualGameProviderByID(ctx, req.ProviderID) @@ -160,7 +159,6 @@ func (s *Service) StartDemoGame(ctx context.Context, req domain.DemoGameRequest) return &res, nil } - func (s *Service) GetBalance(ctx context.Context, req domain.BalanceRequest) (*domain.BalanceResponse, error) { // Retrieve player's real balance from wallet Service playerIDInt64, err := strconv.ParseInt(req.PlayerID, 10, 64) @@ -595,3 +593,25 @@ func (s *Service) GetHugeWins(ctx context.Context, req domain.HugeWinsRequest) ( return &res, nil } + +func (s *Service) GetCreditBalances(ctx context.Context, brandID string) ([]domain.CreditBalance, error) { + if brandID == "" { + return nil, fmt.Errorf("brandID cannot be empty") + } + + // Prepare request body + body := map[string]any{ + "brandId": brandID, + } + + // Call the VeliGames API + var res struct { + Credits []domain.CreditBalance `json:"credits"` + } + + if err := s.client.post(ctx, "/report-api/public/credit/balances", body, nil, &res); err != nil { + return nil, fmt.Errorf("failed to fetch credit balances: %w", err) + } + + return res.Credits, nil +} diff --git a/internal/web_server/app.go b/internal/web_server/app.go index fa016c0..62d8dfb 100644 --- a/internal/web_server/app.go +++ b/internal/web_server/app.go @@ -30,6 +30,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/atlas" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt" @@ -43,45 +44,47 @@ import ( ) type App struct { - veliVirtualGameService veli.VeliVirtualGameService - telebirrSvc *telebirr.TelebirrService - arifpaySvc *arifpay.ArifpayService - santimpaySvc *santimpay.SantimPayService - issueReportingSvc *issuereporting.Service - instSvc *institutions.Service - currSvc *currency.Service - fiber *fiber.App - aleaVirtualGameService alea.AleaVirtualGameService - recommendationSvc recommendation.RecommendationService - cfg *config.Config - logger *slog.Logger - NotidicationStore *notificationservice.Service - referralSvc referralservice.ReferralStore - bonusSvc *bonus.Service - port int - settingSvc *settings.Service - authSvc *authentication.Service - userSvc *user.Service - betSvc *bet.Service - virtualGameSvc virtualgameservice.VirtualGameService - reportSvc *report.Service - chapaSvc *chapa.Service - walletSvc *wallet.Service - transactionSvc *transaction.Service - ticketSvc *ticket.Service - branchSvc *branch.Service - companySvc *company.Service - validator *customvalidator.CustomValidator - JwtConfig jwtutil.JwtConfig - Logger *slog.Logger - prematchSvc *odds.ServiceImpl - eventSvc event.Service - leagueSvc league.Service - resultSvc *result.Service - mongoLoggerSvc *zap.Logger + atlasVirtualGameService atlas.AtlasVirtualGameService + veliVirtualGameService veli.VeliVirtualGameService + telebirrSvc *telebirr.TelebirrService + arifpaySvc *arifpay.ArifpayService + santimpaySvc *santimpay.SantimPayService + issueReportingSvc *issuereporting.Service + instSvc *institutions.Service + currSvc *currency.Service + fiber *fiber.App + aleaVirtualGameService alea.AleaVirtualGameService + recommendationSvc recommendation.RecommendationService + cfg *config.Config + logger *slog.Logger + NotidicationStore *notificationservice.Service + referralSvc referralservice.ReferralStore + bonusSvc *bonus.Service + port int + settingSvc *settings.Service + authSvc *authentication.Service + userSvc *user.Service + betSvc *bet.Service + virtualGameSvc virtualgameservice.VirtualGameService + reportSvc *report.Service + chapaSvc *chapa.Service + walletSvc *wallet.Service + transactionSvc *transaction.Service + ticketSvc *ticket.Service + branchSvc *branch.Service + companySvc *company.Service + validator *customvalidator.CustomValidator + JwtConfig jwtutil.JwtConfig + Logger *slog.Logger + prematchSvc *odds.ServiceImpl + eventSvc event.Service + leagueSvc league.Service + resultSvc *result.Service + mongoLoggerSvc *zap.Logger } func NewApp( + atlasVirtualGameService atlas.AtlasVirtualGameService, veliVirtualGameService veli.VeliVirtualGameService, telebirrSvc *telebirr.TelebirrService, arifpaySvc *arifpay.ArifpayService, @@ -132,15 +135,16 @@ func NewApp( })) s := &App{ + atlasVirtualGameService: atlasVirtualGameService, veliVirtualGameService: veliVirtualGameService, - telebirrSvc: telebirrSvc, - arifpaySvc: arifpaySvc, - santimpaySvc: santimpaySvc, - issueReportingSvc: issueReportingSvc, - instSvc: instSvc, - currSvc: currSvc, - fiber: app, - port: port, + telebirrSvc: telebirrSvc, + arifpaySvc: arifpaySvc, + santimpaySvc: santimpaySvc, + issueReportingSvc: issueReportingSvc, + instSvc: instSvc, + currSvc: currSvc, + fiber: app, + port: port, settingSvc: settingSvc, authSvc: authSvc, diff --git a/internal/web_server/handlers/atlas.go b/internal/web_server/handlers/atlas.go new file mode 100644 index 0000000..7708336 --- /dev/null +++ b/internal/web_server/handlers/atlas.go @@ -0,0 +1,398 @@ +package handlers + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "strings" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/gofiber/fiber/v2" +) + +// InitAtlasGame godoc +// @Summary Start an Atlas virtual game session +// @Description Initializes a game session for the given player using Atlas virtual game provider +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.AtlasGameInitRequest true "Start game input" +// @Success 200 {object} domain.Response{data=domain.AtlasGameInitResponse} +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /api/v1/atlas/init-game [post] +func (h *Handler) InitAtlasGame(c *fiber.Ctx) error { + // Retrieve user ID from context + userId, ok := c.Locals("user_id").(int64) + if !ok { + return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{ + Error: "missing user id", + Message: "Unauthorized", + }) + } + + var req domain.AtlasGameInitRequest + if err := c.BodyParser(&req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid request body", + Error: err.Error(), + }) + } + + // Attach user ID to request + req.PlayerID = fmt.Sprintf("%d", userId) + + // Default language if not provided + if req.Language == "" { + req.Language = "en" + } + + // Default currency if not provided + if req.Currency == "" { + req.Currency = "USD" + } + + // Call the service + res, err := h.atlasVirtualGameSvc.InitGame(context.Background(), req) + if err != nil { + log.Println("InitAtlasGame error:", err) + + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to initialize Atlas game", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(domain.Response{ + Message: "Game initialized successfully", + Data: res, + StatusCode: fiber.StatusOK, + Success: true, + }) +} + +// AtlasGetUserDataCallback godoc +// @Summary Atlas Get User Data callback +// @Description Callback endpoint for Atlas game server to fetch player balance +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.AtlasGetUserDataRequest true "Get user data input" +// @Success 200 {object} domain.AtlasGetUserDataResponse +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /account [post] +func (h *Handler) AtlasGetUserDataCallback(c *fiber.Ctx) error { + var req domain.AtlasGetUserDataRequest + if err := c.BodyParser(&req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid request body", + Error: err.Error(), + }) + } + + // Optional: validate casino_id matches your configured Atlas casino + if req.CasinoID != h.Cfg.Atlas.CasinoID { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid casino_id", + Error: "unauthorized request", + }) + } + + // Call service to get player data + res, err := h.atlasVirtualGameSvc.GetUserData(c.Context(), req) + if err != nil { + log.Println("AtlasGetUserDataCallback error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to fetch user data", + Error: err.Error(), + }) + } + + // Return Atlas expected response + return c.JSON(res) +} + +// HandleAtlasBetWin godoc +// @Summary Atlas BetWin callback +// @Description Processes a Bet and Win request from Atlas provider +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.AtlasBetWinRequest true "Atlas BetWin input" +// @Success 200 {object} domain.AtlasBetWinResponse +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /betwin [post] +func (h *Handler) HandleAtlasBetWin(c *fiber.Ctx) error { + body := c.Body() + if len(body) == 0 { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Empty request body", + Error: "Request body cannot be empty", + }) + } + + var req domain.AtlasBetWinRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid Atlas BetWin request", + Error: err.Error(), + }) + } + + res, err := h.atlasVirtualGameSvc.ProcessBetWin(c.Context(), req) + if err != nil { + // Handle known errors specifically + code := fiber.StatusInternalServerError + errMsg := err.Error() + + switch { + case errors.Is(err, domain.ErrInsufficientBalance): + code = fiber.StatusBadRequest + errMsg = "INSUFFICIENT_BALANCE" + case strings.Contains(err.Error(), "invalid casino_id"): + code = fiber.StatusBadRequest + case strings.Contains(err.Error(), "invalid playerID"): + code = fiber.StatusBadRequest + } + + return c.Status(code).JSON(domain.ErrorResponse{ + Message: "Failed to process Atlas BetWin", + Error: errMsg, + }) + } + + return c.Status(fiber.StatusOK).JSON(res) +} + +// HandleRoundResult godoc +// @Summary Atlas Round Result callback +// @Description Processes a round result from Atlas or other providers +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.RoundResultRequest true "Round result input" +// @Success 200 {object} domain.RoundResultResponse +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /result [post] +func (h *Handler) HandleRoundResult(c *fiber.Ctx) error { + body := c.Body() + if len(body) == 0 { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Empty request body", + Error: "Request body cannot be empty", + }) + } + + var req domain.RoundResultRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid RoundResult request", + Error: err.Error(), + }) + } + + res, err := h.atlasVirtualGameSvc.ProcessRoundResult(c.Context(), req) + if err != nil { + code := fiber.StatusInternalServerError + errMsg := err.Error() + + // Validation errors + if strings.Contains(err.Error(), "missing player_id") || strings.Contains(err.Error(), "missing transaction_id") { + code = fiber.StatusBadRequest + } + + return c.Status(code).JSON(domain.ErrorResponse{ + Message: "Failed to process round result", + Error: errMsg, + }) + } + + return c.Status(fiber.StatusOK).JSON(res) +} + +// HandleRollback godoc +// @Summary Atlas Rollback callback +// @Description Processes a rollback request from Atlas or other providers +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.RollbackRequest true "Rollback request input" +// @Success 200 {object} domain.RollbackResponse +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /rollback [post] +func (h *Handler) HandleRollback(c *fiber.Ctx) error { + body := c.Body() + if len(body) == 0 { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Empty request body", + Error: "Request body cannot be empty", + }) + } + + var req domain.RollbackRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid Rollback request", + Error: err.Error(), + }) + } + + res, err := h.atlasVirtualGameSvc.ProcessRollBack(c.Context(), req) + if err != nil { + code := fiber.StatusInternalServerError + errMsg := err.Error() + + // Validation errors + if strings.Contains(err.Error(), "missing player_id") || strings.Contains(err.Error(), "missing transaction_id") { + code = fiber.StatusBadRequest + } + + return c.Status(code).JSON(domain.ErrorResponse{ + Message: "Failed to process rollback", + Error: errMsg, + }) + } + + return c.Status(fiber.StatusOK).JSON(res) +} + +// CreateFreeSpin godoc +// @Summary Create free spins for a player +// @Description Sends a request to Atlas to create free spins/bets for a given player +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.FreeSpinRequest true "Free spin input" +// @Success 200 {object} domain.Response{data=domain.FreeSpinResponse} +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /api/v1/atlas/freespin [post] +func (h *Handler) CreateFreeSpin(c *fiber.Ctx) error { + // Get the authenticated user ID + userId, ok := c.Locals("user_id").(int64) + if !ok { + return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{ + Error: "missing user id", + Message: "Unauthorized", + }) + } + + var req domain.FreeSpinRequest + if err := c.BodyParser(&req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid request body", + Error: err.Error(), + }) + } + + // Attach player ID from authenticated user + req.PlayerID = fmt.Sprintf("%d", userId) + + res, err := h.atlasVirtualGameSvc.CreateFreeSpin(c.Context(), req) + if err != nil { + log.Println("CreateFreeSpin error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to create free spins", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(domain.Response{ + Message: "Free spins created successfully", + Data: res, + StatusCode: fiber.StatusOK, + Success: true, + }) +} + +// FreeSpinResultCallback godoc +// @Summary Free Spin/Bet result callback +// @Description Handles the result of a free spin/bet from the game server +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.FreeSpinResultRequest true "Free spin result input" +// @Success 200 {object} domain.FreeSpinResultResponse +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /freespin [post] +func (h *Handler) FreeSpinResultCallback(c *fiber.Ctx) error { + // Read raw request body + body := c.Body() + if len(body) == 0 { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Empty request body", + Error: "Request body cannot be empty", + }) + } + + // Unmarshal into FreeSpinResultRequest + var req domain.FreeSpinResultRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid free spin result request", + Error: err.Error(), + }) + } + + // Process the free spin result + res, err := h.atlasVirtualGameSvc.ProcessFreeSpinResult(c.Context(), req) + if err != nil { + log.Println("FreeSpinResultCallback error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to process free spin result", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(res) +} + +// JackpotCallback godoc +// @Summary Jackpot result callback +// @Description Handles the jackpot result from the game server +// @Tags Virtual Games - Atlas +// @Accept json +// @Produce json +// @Param request body domain.JackpotRequest true "Jackpot result input" +// @Success 200 {object} domain.JackpotResponse +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /jackpot [post] +func (h *Handler) JackpotCallback(c *fiber.Ctx) error { + // Read raw request body + body := c.Body() + if len(body) == 0 { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Empty request body", + Error: "Request body cannot be empty", + }) + } + + // Unmarshal into JackpotRequest + var req domain.JackpotRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid jackpot request", + Error: err.Error(), + }) + } + + // Process the jackpot + res, err := h.atlasVirtualGameSvc.ProcessJackPot(c.Context(), req) + if err != nil { + log.Println("JackpotCallback error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to process jackpot", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(res) +} diff --git a/internal/web_server/handlers/handlers.go b/internal/web_server/handlers/handlers.go index a59dbc9..9446195 100644 --- a/internal/web_server/handlers/handlers.go +++ b/internal/web_server/handlers/handlers.go @@ -30,6 +30,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/atlas" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt" @@ -38,39 +39,40 @@ import ( ) type Handler struct { - telebirrSvc *telebirr.TelebirrService - arifpaySvc *arifpay.ArifpayService - santimpaySvc *santimpay.SantimPayService - issueReportingSvc *issuereporting.Service - instSvc *institutions.Service - currSvc *currency.Service - logger *slog.Logger - settingSvc *settings.Service - notificationSvc *notificationservice.Service - userSvc *user.Service - referralSvc referralservice.ReferralStore - bonusSvc *bonus.Service - reportSvc report.ReportStore - chapaSvc *chapa.Service - walletSvc *wallet.Service - transactionSvc *transaction.Service - ticketSvc *ticket.Service - betSvc *bet.Service - branchSvc *branch.Service - companySvc *company.Service - prematchSvc *odds.ServiceImpl - eventSvc event.Service - leagueSvc league.Service - virtualGameSvc virtualgameservice.VirtualGameService - aleaVirtualGameSvc alea.AleaVirtualGameService - veliVirtualGameSvc veli.VeliVirtualGameService - recommendationSvc recommendation.RecommendationService - authSvc *authentication.Service - resultSvc result.Service - jwtConfig jwtutil.JwtConfig - validator *customvalidator.CustomValidator - Cfg *config.Config - mongoLoggerSvc *zap.Logger + telebirrSvc *telebirr.TelebirrService + arifpaySvc *arifpay.ArifpayService + santimpaySvc *santimpay.SantimPayService + issueReportingSvc *issuereporting.Service + instSvc *institutions.Service + currSvc *currency.Service + logger *slog.Logger + settingSvc *settings.Service + notificationSvc *notificationservice.Service + userSvc *user.Service + referralSvc referralservice.ReferralStore + bonusSvc *bonus.Service + reportSvc report.ReportStore + chapaSvc *chapa.Service + walletSvc *wallet.Service + transactionSvc *transaction.Service + ticketSvc *ticket.Service + betSvc *bet.Service + branchSvc *branch.Service + companySvc *company.Service + prematchSvc *odds.ServiceImpl + eventSvc event.Service + leagueSvc league.Service + virtualGameSvc virtualgameservice.VirtualGameService + aleaVirtualGameSvc alea.AleaVirtualGameService + veliVirtualGameSvc veli.VeliVirtualGameService + atlasVirtualGameSvc atlas.AtlasVirtualGameService + recommendationSvc recommendation.RecommendationService + authSvc *authentication.Service + resultSvc result.Service + jwtConfig jwtutil.JwtConfig + validator *customvalidator.CustomValidator + Cfg *config.Config + mongoLoggerSvc *zap.Logger } func New( @@ -92,6 +94,7 @@ func New( virtualGameSvc virtualgameservice.VirtualGameService, aleaVirtualGameSvc alea.AleaVirtualGameService, veliVirtualGameSvc veli.VeliVirtualGameService, + atlasVirtualGameSvc atlas.AtlasVirtualGameService, recommendationSvc recommendation.RecommendationService, userSvc *user.Service, transactionSvc *transaction.Service, @@ -109,38 +112,39 @@ func New( mongoLoggerSvc *zap.Logger, ) *Handler { return &Handler{ - telebirrSvc: telebirrSvc, - arifpaySvc: arifpaySvc, - santimpaySvc: santimpaySvc, - issueReportingSvc: issueReportingSvc, - instSvc: instSvc, - currSvc: currSvc, - logger: logger, - settingSvc: settingSvc, - notificationSvc: notificationSvc, - reportSvc: reportSvc, - chapaSvc: chapaSvc, - walletSvc: walletSvc, - referralSvc: referralSvc, - bonusSvc: bonusSvc, - validator: validator, - userSvc: userSvc, - transactionSvc: transactionSvc, - ticketSvc: ticketSvc, - betSvc: betSvc, - branchSvc: branchSvc, - companySvc: companySvc, - prematchSvc: prematchSvc, - eventSvc: eventSvc, - leagueSvc: leagueSvc, - virtualGameSvc: virtualGameSvc, - aleaVirtualGameSvc: aleaVirtualGameSvc, - veliVirtualGameSvc: veliVirtualGameSvc, - recommendationSvc: recommendationSvc, - authSvc: authSvc, - resultSvc: resultSvc, - jwtConfig: jwtConfig, - Cfg: cfg, - mongoLoggerSvc: mongoLoggerSvc, + telebirrSvc: telebirrSvc, + arifpaySvc: arifpaySvc, + santimpaySvc: santimpaySvc, + issueReportingSvc: issueReportingSvc, + instSvc: instSvc, + currSvc: currSvc, + logger: logger, + settingSvc: settingSvc, + notificationSvc: notificationSvc, + reportSvc: reportSvc, + chapaSvc: chapaSvc, + walletSvc: walletSvc, + referralSvc: referralSvc, + bonusSvc: bonusSvc, + validator: validator, + userSvc: userSvc, + transactionSvc: transactionSvc, + ticketSvc: ticketSvc, + betSvc: betSvc, + branchSvc: branchSvc, + companySvc: companySvc, + prematchSvc: prematchSvc, + eventSvc: eventSvc, + leagueSvc: leagueSvc, + virtualGameSvc: virtualGameSvc, + aleaVirtualGameSvc: aleaVirtualGameSvc, + veliVirtualGameSvc: veliVirtualGameSvc, + atlasVirtualGameSvc: atlasVirtualGameSvc, + recommendationSvc: recommendationSvc, + authSvc: authSvc, + resultSvc: resultSvc, + jwtConfig: jwtConfig, + Cfg: cfg, + mongoLoggerSvc: mongoLoggerSvc, } } diff --git a/internal/web_server/handlers/odd_handler.go b/internal/web_server/handlers/odd_handler.go index bf89c84..15585ff 100644 --- a/internal/web_server/handlers/odd_handler.go +++ b/internal/web_server/handlers/odd_handler.go @@ -15,7 +15,7 @@ import ( // @Tags prematch // @Accept json // @Produce json -// @Success 200 {array} domain.Odd +// @Success 200 {array} domain.OddMarketFilter // @Failure 500 {object} response.APIResponse // @Router /api/v1/odds [get] func (h *Handler) GetAllOdds(c *fiber.Ctx) error { @@ -59,7 +59,7 @@ func (h *Handler) GetAllOdds(c *fiber.Ctx) error { // @Tags prematch // @Accept json // @Produce json -// @Success 200 {array} domain.Odd +// @Success 200 {array} domain.OddMarketFilter // @Failure 500 {object} response.APIResponse // @Router /api/v1/{tenant_slug}/odds [get] func (h *Handler) GetAllTenantOdds(c *fiber.Ctx) error { @@ -201,7 +201,7 @@ func (h *Handler) GetTenantOddsByMarketID(c *fiber.Ctx) error { // @Param upcoming_id path string true "Upcoming Event ID (FI)" // @Param limit query int false "Number of results to return (default: 10)" // @Param offset query int false "Number of results to skip (default: 0)" -// @Success 200 {array} domain.Odd +// @Success 200 {array} domain.OddMarketWithEventFilter // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/odds/upcoming/{upcoming_id} [get] @@ -252,7 +252,7 @@ func (h *Handler) GetOddsByUpcomingID(c *fiber.Ctx) error { // @Param upcoming_id path string true "Upcoming Event ID (FI)" // @Param limit query int false "Number of results to return (default: 10)" // @Param offset query int false "Number of results to skip (default: 0)" -// @Success 200 {array} domain.Odd +// @Success 200 {array} domain.OddMarketFilter // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /api/v1/{tenant_slug}/odds/upcoming/{upcoming_id} [get] diff --git a/internal/web_server/handlers/veli_games.go b/internal/web_server/handlers/veli_games.go index 0f299f5..b5f5f02 100644 --- a/internal/web_server/handlers/veli_games.go +++ b/internal/web_server/handlers/veli_games.go @@ -103,7 +103,6 @@ func (h *Handler) GetGamesByProvider(c *fiber.Ctx) error { }) } - // StartGame godoc // @Summary Start a real game session // @Description Starts a real VeliGames session with the given player and game info @@ -167,7 +166,6 @@ func (h *Handler) StartGame(c *fiber.Ctx) error { }) } - // StartDemoGame godoc // @Summary Start a demo game session // @Description Starts a demo session of the specified game (must support demo mode) @@ -220,7 +218,6 @@ func (h *Handler) StartDemoGame(c *fiber.Ctx) error { }) } - func (h *Handler) GetBalance(c *fiber.Ctx) error { var req domain.BalanceRequest if err := c.BodyParser(&req); err != nil { @@ -395,3 +392,41 @@ func (h *Handler) GetHugeWins(c *fiber.Ctx) error { Success: true, }) } + +// GetCreditBalances godoc +// @Summary Get VeliGames credit balances for a brand +// @Description Fetches current credit balances per currency for the specified brand +// @Tags Virtual Games - VeliGames +// @Accept json +// @Produce json +// @Param brandId query string true "Brand ID" +// @Success 200 {object} domain.Response{data=[]domain.CreditBalance} +// @Failure 400 {object} domain.ErrorResponse +// @Failure 502 {object} domain.ErrorResponse +// @Router /api/v1/veli/credit-balances [get] +func (h *Handler) GetCreditBalances(c *fiber.Ctx) error { + brandID := c.Query("brandId", h.Cfg.VeliGames.BrandID) // Default brand if not provided + + if brandID == "" { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Brand ID is required", + Error: "missing brandId", + }) + } + + res, err := h.veliVirtualGameSvc.GetCreditBalances(c.Context(), brandID) + if err != nil { + log.Println("GetCreditBalances error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to fetch credit balances", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(domain.Response{ + Message: "Credit balances fetched successfully", + Data: res, + StatusCode: fiber.StatusOK, + Success: true, + }) +} diff --git a/internal/web_server/handlers/virtual_games_hadlers.go b/internal/web_server/handlers/virtual_games_hadlers.go index ade2b8b..058f4e0 100644 --- a/internal/web_server/handlers/virtual_games_hadlers.go +++ b/internal/web_server/handlers/virtual_games_hadlers.go @@ -255,11 +255,26 @@ func (h *Handler) HandleBet(c *fiber.Ctx) error { }) } - // Try parsing as Veli bet request - var veliReq domain.BetRequest - if err := json.Unmarshal(body, &veliReq); err == nil && veliReq.SessionID != "" && veliReq.BrandID != "" { - // Process as Veli - res, err := h.veliVirtualGameSvc.ProcessBet(c.Context(), veliReq) + // Identify the provider based on request structure + provider, err := IdentifyBetProvider(body) + if err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Unrecognized request format", + Error: err.Error(), + }) + } + + switch provider { + case "veli": + var req domain.BetRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid Veli bet request", + Error: err.Error(), + }) + } + + res, err := h.veliVirtualGameSvc.ProcessBet(c.Context(), req) if err != nil { if errors.Is(err, veli.ErrDuplicateTransaction) { return c.Status(fiber.StatusConflict).JSON(domain.ErrorResponse{ @@ -267,19 +282,23 @@ func (h *Handler) HandleBet(c *fiber.Ctx) error { Error: "DUPLICATE_TRANSACTION", }) } - return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ Message: "Veli bet processing failed", Error: err.Error(), }) } return c.JSON(res) - } - // Try parsing as PopOK bet request - var popokReq domain.PopOKBetRequest - if err := json.Unmarshal(body, &popokReq); err == nil && popokReq.ExternalToken != "" { - // Process as PopOK - resp, err := h.virtualGameSvc.ProcessBet(c.Context(), &popokReq) + case "popok": + var req domain.PopOKBetRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid PopOK bet request", + Error: err.Error(), + }) + } + + resp, err := h.virtualGameSvc.ProcessBet(c.Context(), &req) if err != nil { code := fiber.StatusInternalServerError switch err.Error() { @@ -294,13 +313,35 @@ func (h *Handler) HandleBet(c *fiber.Ctx) error { }) } return c.JSON(resp) - } - // If neither works - return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ - Message: "Unsupported provider", - Error: "Request format doesn't match any supported provider", - }) + case "atlas": + var req domain.AtlasBetRequest + if err := json.Unmarshal(body, &req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Invalid Atlas bet request", + Error: err.Error(), + }) + } + + resp, err := h.atlasVirtualGameSvc.ProcessBet(c.Context(), req) + if err != nil { + // code := fiber.StatusInternalServerError + // if errors.Is(err, ErrDuplicateTransaction) { + // code = fiber.StatusConflict + // } + return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ + Message: "Atlas bet processing failed", + Error: err.Error(), + }) + } + return c.JSON(resp) + + default: + return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ + Message: "Unsupported provider", + Error: "Request format doesn't match any supported provider", + }) + } } // identifyProvider examines the request body to determine the provider @@ -653,6 +694,17 @@ func IdentifyBetProvider(body []byte) (string, error) { } } + var atlasCheck struct { + CasinoID string `json:"casino_id"` + SessionID string `json:"session_id"` + } + + if json.Unmarshal(body, &atlasCheck) == nil { + if atlasCheck.CasinoID != "" && atlasCheck.SessionID != "" { + return "atlas", nil + } + } + return "", fmt.Errorf("could not identify provider from request structure") } diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 789b670..55ddaca 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -38,6 +38,7 @@ func (a *App) initAppRoutes() { a.virtualGameSvc, a.aleaVirtualGameService, a.veliVirtualGameService, + a.atlasVirtualGameService, a.recommendationSvc, a.userSvc, a.transactionSvc, @@ -306,6 +307,17 @@ func (a *App) initAppRoutes() { a.fiber.Post("/balance", h.GetBalance) groupV1.Post("/veli/gaming-activity", a.authMiddleware, h.GetGamingActivity) groupV1.Post("/veli/huge-wins", a.authMiddleware, h.GetHugeWins) + groupV1.Post("/veli/credit-balances", a.authMiddleware, h.GetCreditBalances) + + //Atlas Virtual Game Routes + groupV1.Post("/atlas/init-game", a.authMiddleware, h.InitAtlasGame) + a.fiber.Post("/account", h.AtlasGetUserDataCallback) + a.fiber.Post("/betwin", h.HandleAtlasBetWin) + a.fiber.Post("/result", h.HandleRoundResult) + a.fiber.Post("/rollback", h.HandleRollback) + a.fiber.Post("/freespin", h.FreeSpinResultCallback) + a.fiber.Post("/jackpot", h.JackpotCallback) + groupV1.Post("/atlas/freespin", a.authMiddleware, h.CreateFreeSpin) //mongoDB logs groupV1.Get("/logs", a.authMiddleware, a.SuperAdminOnly, handlers.GetLogsHandler(context.Background()))