--[[ // Http.lua // API for all web endpoints // Calls are async // Any calls to watrbx.wtf need to use game:HttpGetAynsc() and game:HttpPostAynsc() // use rbxGetAsync() and rbxPostAsync() // Any calls to api.watrbx.wtf should use HttpRbxApiService // use rbxApiGetAsync() and rbxApiPostAsync() // NOTE: You cannot currently get thumbnails with this API (please see the Thumbnail module), because // Roblox GUIs cannot accept rbxcnd.com for the Image property. ]] --[[ Services ]]-- local HttpService = game:GetService('HttpService') local HttpRbxApiService = game:GetService('HttpRbxApiService') local Http = {} local BaseUrl = game:GetService('ContentProvider').BaseUrl:lower() BaseUrl = string.gsub(BaseUrl, "/m.", "/www.") -- TODO: There are some calls that fail when using https. Wait for web to fix. BaseUrl = string.gsub(BaseUrl, "http://", "https://") AssetGameBaseUrl = string.gsub(BaseUrl, "https://www.", "https://assetgame.") Http.BaseUrl = BaseUrl Http.AssetGameBaseUrl = AssetGameBaseUrl --[[ Helper Functions ]]-- local function decodeJSON(json) local success, result = pcall(function() return HttpService:JSONDecode(json) end) if not success then print("decodeJSON() failed because", result, "Input:", json) return nil end return result end local function rbxGetAsync(path, returnRaw) local success, result = pcall(function() return game:HttpGetAsync(path) end) -- if not success then print(path, "rbxGetAsync() failed because", result) return nil end if returnRaw then return result end return decodeJSON(result) end local function rbxPostAsync(path, params, contentType) local success, result = pcall(function() return game:HttpPostAsync(path, params, contentType) end) -- if not success then print(path, "rbxPostAsync() failed because", result) return nil end return decodeJSON(result) end local function rbxApiGetAsync(path, useHttps) local success, result = pcall(function() return HttpRbxApiService:GetAsync(path, useHttps) end) -- if not success then print(path, "rbxApiGetAsync() failed because", result) return nil end return decodeJSON(result) end local function rbxApiPostAsync(path, params, useHttps, throttlePriority, contentType) local success, result = pcall(function() return HttpRbxApiService:PostAsync(path, params, useHttps, throttlePriority, contentType) end) -- if not success then print(path..params, "rbxApiPostAsync() failed because", result) return nil end return decodeJSON(result) end --[[ Public API ]]-- --[[ Helper Functions ]]-- function Http.DecodeJSON(json) return decodeJSON(json) end --[[ Games Endpoints ]]-- --[[ // Return Array of tables // Table Keys // Id - number // Name - string // TimeOptionsAvailable - boolean // DefaultTimeOption - number // GenresOptionsAvailable - boolean ]] function Http.GetGameSortsAsync() return rbxGetAsync(BaseUrl..'games/default-sorts') end --[[ All Sorts return the following json // Returns Array of Tables // Table Keys // CreatorID - number // CreatorName- string // CreatorUrl - string // Plays - number // Price - number // ProductID - number // IsOwned - boolean // IsVotingEnabled - boolean // TotalUpVotes - number // TotalDownVotes - number // TotalBought - number // UniverseID - number // HasErrorOcurred - boolean // Name - string // PlaceID - number // PlayerCount - number // ImageId - number ]] function Http.GetSortAsync(startRows, maxRows, sortId, timeFilter) local path = string.format("%sgames/list-json?sortFilter=%d&StartRows=%d&MaxRows=%d&searchAllGames=false&filterByDeviceType=true", BaseUrl, sortId, startRows, maxRows) if timeFilter then path = string.format("%s&timeFilter=%d", path, timeFilter) end return rbxGetAsync(path) end function Http.GetUserFavoritesAsync(startRows, maxRows) local path = string.format("%sgames/moreresultsuncached-json?sortFilter=MyFavorite&StartRows=%d&MaxRows=%d&searchAllGames=true&filterByDeviceType=true", BaseUrl, startRows, maxRows) return rbxGetAsync(path) end function Http.GetUserRecentAsync(startRows, maxRows) local path = string.format("%sgames/moreresultsuncached-json?sortFilter=MyRecent&StartRows=%d&MaxRows=%d&searchAllGames=true&filterByDeviceType=true", BaseUrl, startRows, maxRows) return rbxGetAsync(path) end function Http.GetUserPlacesAsync(startIndex, pageSize, userid) local path = string.format("%sgames/list-users-games-json?userid=%d&startIndex=%d&pageSize=%d", BaseUrl, userid, startIndex, pageSize) return rbxGetAsync(path) end -- Here for future use function Http.SearchGamesAsync(startRows, maxRows, keyword) local path = string.format("%sgames/list-json?keyword=%s&StartRows=%d&MaxRows=%d", BaseUrl, startRows, maxRows) return rbxGetAsync(path) end --[[ Asset Endpoints ]]-- --[[ // Returns Table // Table Keys // Url - string // Final - boolean ]] function Http.GetAssetThumbnailFinalAsync(assetId, width, height, format) return rbxGetAsync(AssetGameBaseUrl..'asset-thumbnail/json?assetId='..tostring(assetId)..'&width='..tostring(width).. '&height='..tostring(height)..'&format='..format) end --[[ // See Above ]] function Http.GetAssetAvatarFinalAsync(userId, width, height, format) local result = rbxGetAsync(BaseUrl..'avatar-thumbnail/json?userId='..tostring(userId)..'&width='..tostring(width).. '&height='..tostring(height)..'&format='..format) return result end function Http.GetOutfitThumbnailFinalAsync(outfitId, width, height, format) local requestData = {['userOutfitId'] = outfitId} local requestDataJson = HttpService:JSONEncode(requestData) local encodedRequestData = requestDataJson and HttpService:UrlEncode(requestDataJson) or "" local url = string.format('%savatar-thumbnails?params=%s', BaseUrl, encodedRequestData) print("Get outfit thumbnail url:", url) local result = rbxGetAsync(url) return result end --[[ Game Endpoints ]]-- --[[ // Return Table // Table Keys // AssetId - number // Name - string // Description - string // Created - string date (m/dd/yyyy) // Updated - string date (m/dd/yyyy) // FavoritedCount - number // Url - string url ex : "/games/192800/Work-at-a-Pizza-Place" // ReportAbuseUrl - string url ex : "/abusereport/asset?id=192800&RedirectUrl=%2fgames%2f192800%2fWork-at-a-Pizza-Place", // IsFavoritedByUser - boolean // IsCreatedByUser - boolean // VisitedCount - number // MaxPlayers - number // Builder - string // BuilderId - number // BuilderUrl - string url ex: "/User.aspx?ID=82471" // IsPlayable - boolean // ReasonProhibited - string // ReasonProhibitedMessage - string // IsBuildersClubOnly - boolean // IsCopyLocked - boolean // IsPersonalServer - boolean // IsPersonalServerOverlay - boolean // BuildersClubOverlay - string // PlayButtonType - string (Enum?) // AssetGenre - string // AssetGenreViewModel - table // DisplayName - string // Id - number // OnlineCount - number // UniverseId - number // UniverseRootPlaceId - number // TotalUpVotes - number // TotalDownVotes - number // UserVote - null (?) // OverridesDefaultAvatar - boolean ]] function Http.GetGameDetailsAsync(placeId) return rbxGetAsync(BaseUrl..'places/api-get-details?assetId='..tostring(placeId)) end --[[ // Returns Table // Table Keys // Id - number // PlaceId - number // ImageId - number // IconUrl - string // IconFinal - boolean // WikiUrl - string // ReleaseDate - string // IconUpdateSuccess - boolean // IconUpdateMessage - string ]] function Http.GetGameIconIdAsync(placeId) return rbxGetAsync(BaseUrl..'places/icons/json?placeId='..tostring(placeId)) end --[[ // Return Table // Table Keys // ShowVotes - boolean // VotingModel - table // ShowVotes - boolean // UpVotes - number // DownVotes - number // CanVote - boolean // UserVote - boolean / null if user has not voted on this game // ReasonForNotVoteable - string // InvalidAssetOrUser, EmailIsVerified, PlayGame ]] function Http.GetGameVotesAsync(placeId) return rbxGetAsync(BaseUrl..'PlaceItem/GameDetailsVotingPanelJson?placeId='..tostring(placeId)) end --[[ // Returns Array of tables - Length should always be 6 // Table Keys // PlaceId - number // GameName - string // GameSeoUrl - string // Creator - table // CreatorName - string // CreatorTargetId - number // CreatorType - number // GameThumbnail - table // Url - string // IsFinal - boolean // AssetId - number // AssetType - number // AssetHash - can be null // ImageId - number, NEW ]] function Http.GetRecommendedGamesAsync(currentPlaceId) return rbxGetAsync(BaseUrl..'Games/GetRecommendedGamesJson?currentPlaceId='..tostring(currentPlaceId)) end --[[ // Returns Table // Table Keys // IsMobile - boolean // IsVideoAutoplayedOnReady - boolean // thumbnailCount - number // thumbnails - array of tables // Tabke Keys // AssetId - number // AssetTypeId - number // Url - string // IsFinal - boolean // AssetHash - can be null ]] function Http.GetGameThumbnailsAsync(placeId) return rbxGetAsync(BaseUrl..'thumbnail/place-thumbnails?placeId='..tostring(placeId)) end --[[ // Returns Table // Table Keys // PlaceId - number // GameBadges - array of tables // BadgeAssetId - number // IsOwned - boolean // Rarity - number // RarityName - string // TotalAwarded - number // TotalAwardedYesterday - number // Created - string // Updated - string // BadgeSeoUrl - string // CreatorId - number // ImageUrl - string (DO NOT USE) // IsImageUrlFinal - boolean // Name - string // Description - string ]] function Http.GetGameBadgeDataAsync(placeId) return rbxGetAsync(BaseUrl..'badges/list-badges-for-place/json?placeId='..tostring(placeId)) end --[[ // Returns Table // Table Keys // PlaceId - number // totalItems - number // IsViewerPlaceOwner - boolean // data - array of tables // PassID - number // PassName - string // TotalSales - number // PriceInRobux - number // PriceInTickets - number // Description - string // UserOwns - boolean // PassItemURL - string // ProductID - number // TotalUpVotes - number // TotalDownVotes - number // UserVote - null if user has not voted // TotalFavorites - number // IsFavoritedByUser - boolean // PlaceOwnerId - number // PlaceOwnerName - string ]] function Http.GetGamePassesAsync(placeId, startIndex, maxRows) return rbxGetAsync(BaseUrl..'Games/GetGamePassesPaged?placeId='..tostring(placeId).. '&startIndex='..tostring(startIndex)..'&maxRows='..tostring(maxRows)) end --[[ // Returns table // Table Keys // PlaceId - number // totalItems - number // IsViewerPlaceOwner - boolean // data - array of tables // Name - string // Description - string // PriceInRobux - number // PriceInTickets - number // ProductID - number // AssetID - number // TotalSales - number // UserOwns - boolean // SellerID - number // SellerName - string // ItemUrl - string // IsRentable - boolean // PromotionID - number // BCRequirement - number // IsForSale - boolean // TotalUpVotes - number // TotalDownVotes - number // UserVote - boolean, can be null if user has not voted // TotalFavorites - number // IsFavoritedByUser - boolean // AffiliateSalePlaceId - number ]] function Http.GetPlaceProductsAsync(placeId, startIndex, maxRows) return rbxGetAsync(BaseUrl..'Games/GetPlaceProductPromotions?placeId='..tostring(placeId).. '&startIndex='..tostring(startIndex)..'&maxRows='..tostring(maxRows)) end --[[ // Returns table // Table Keys // PlaceId - number // TotalCollectionSize - number // ShowShutdownAllButton - boolean // Collection - Array of tables // Table Keys // PlaceId - number // Capacity - number // UserCanJoin - boolean // ServerIpAddress - string // Fps - number // Guid - string // JoinScript - string // ShowSlowGameMessage - boolean // Ping - number // CurrentPlayers - array of tables // Table Keys // Id - number // Username - string // Thumbnail - table // Table Keys // AssetId - number // AssetTypeId - number // Url - string // IsFinal - boolean // AssetHash - can be null ]] function Http.GetGameInstancesAsync(placeId, startIndex) return rbxGetAsync(BaseUrl..'Games/GetGameInstancesJson?placeId='..tostring(placeId)..'&startIndex='..tostring(startIndex)) end --[[ // Returns table // Table Keys // success - boolean // message - string (is Whoa. Slow Down.) ]] function Http.PostFavoriteToggleAsync(assetID) return rbxPostAsync(BaseUrl..'favorite/toggle?assetID='..tostring(assetID), 'favoriteToggle') end -- TODO: Need to test flood check --[[ // Returns Table // Table Keys // Success - boolean // Model - table // ModalType - string | Will be FloodCheckThresholdMet, PlayGame, EmailIsVerified // Table Keys // UserVote - boolean // ShowVotes - boolean // CanVote - boolean // DownVotes - number // UpVotes - number ]] -- status can be true, false or null (null is a neutral vote) function Http.PostGameVoteAsync(assetId, status) return rbxPostAsync(BaseUrl..'voting/vote?assetId='..tostring(assetId)..'&vote='..tostring(status), 'vote') end --[[ Social ]]-- --[[ // Returns Table // Table Keys // GameId - number (can be null) // IsOnline - boolean // LastOnline - string // LastLocation - string // LocationType - number // PlaceId - number (can be null) ]] function Http.GetUserPresenceAsync(userId) return rbxApiGetAsync('users/'..tostring(userId)..'/onlinestatus', true) end --[[ // Returns table // Table Keys // UserPresences - array of tables // Table Keys // VisitorId - number // GameId - number or null // IsOnline - boolean // LastOnline - string // LastLocation - string // LocationType - number/enum // PlaceId - number ]] function Http.GetUsersOnlinePresenceAsync(listOfUsers) --rbxApiPostAsync(path, params, useHttps, throttlePriority, contentType) return rbxApiPostAsync('users/online-status', listOfUsers, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationJson) end --[[ // Returns Table // Table Keys // UserId - number // TotalFriends - number // CurrentPage - number // PageSize - number // TotalPages - number // Friends - Array of Tables // Table Keys // UserId - number // Username - string // AvatarUri - string // AvatarFinal - boolean // InvitationId - number // FriendshipStatus - number // OnlineStatus - table // Table Keys // LocationOrLastSeen - string // ImageUrl - string // AlternateText - string ]] function Http.GetFriendsAsync(userId, currentPage, pageSize) return rbxGetAsync(BaseUrl..'friends/json?userId='..tostring(userId)..'¤tPage='..tostring(currentPage)..'&pageSize='..tostring(pageSize).. '&friendsType=1') end --[[ // See Http.GetFriendsAsync ]] function Http.GetRequestedFriendsAsync(userId, currentPage, pageSize) return rbxGetAsync(BaseUrl..'friends/json?userId='..tostring(userId)..'¤tPage='..tostring(currentPage)..'&pageSize='..tostring(pageSize).. '&friendsType=3') end --[[ // Returns array of tables // Table Keys // VisitorId - number // GameId - string (hash) // IsOnline - boolean // LastOnline - string // LastLocation - string // LocationType - number (enum) // PlaceId - number ]] function Http.GetOnlineFriendsAsync() return rbxApiGetAsync('my/friendsonline', true) end --[[ // Returns Table ]] function Http.GetPlatformUserBalanceAsync() return rbxApiGetAsync('my/platform-currency-budget', true) end function Http.GetTotalUserBalanceAsync() return rbxApiGetAsync('currency/balance', true) end --[[ // Returns true if the user owns the asset, otherwise, returns false ]] function Http.GetUserOwnsAssetAsync(userId, assetId) -- local BaseUrl = 'http://api.sitetest2.watrbx.local/' return rbxApiGetAsync(BaseUrl..'ownership/hasasset?userId='..tostring(userId)..'&assetId='..tostring(assetId), false) end --[[ // Returns Table // Table Keys // IsValid - boolean // Data - Table of keys // Table Keys // TotalItems - number // Start - number // End - number // Page - number // Items - Array of tables // Table Keys // Item - Table // Table Keys // AssetId - number // Name - string // Creator - Table // Table Keys // Id - number // Name - string // Type - number // Product - Table // Table Keys // PriceInRobux - number (nullable) // PriceInTickets - - number (nullable) // IsForSale - boolean // IsPublicDomain - boolean // IsResellable - boolean // IsLimitedEdition - boolean // IsUnique - boolean // ExpireTime - time (nullable) // IsExpired - boolean // OTHER JUNK "PrivateServer":null, "Thumbnail": {"Final":true,"Url":"http://t4.watrbx.wtf/213527c418b9ea4fc7bbcfb79afd770f","RetryUrl":null} }, ]] function Http.GetUserOwnedPackagesAsync(userId, currentPage) currentPage = currentPage or 1 local packageAssetIdType = 32 -- return rbxGetAsync('http://www.sitetest2.watrbx.local/' ..'users/inventory/list-json?userId='..tostring(userId).. -- '&assetTypeId='..tostring(packageAssetIdType)..'&pageNumber='..tostring(currentPage)) return rbxGetAsync(BaseUrl..'users/inventory/list-json?userId='..tostring(userId).. '&assetTypeId='..tostring(packageAssetIdType)..'&pageNumber='..tostring(currentPage)) end function Http.GetMyUserOutfitsAsync(startIndex, count) startIndex = startIndex or 0 count = count or 20 local url = string.format('appearance/get-my-user-outfits?startIndex=%d&count=%d', startIndex, count) return rbxApiGetAsync(url, true) end function Http.GetCharactersAssetsAsync(userId) local url = string.format(AssetGameBaseUrl..'asset/characterfetch.ashx?userId=%d', userId) return rbxGetAsync(url, true) end function Http.PostWearUserOutfitAsync(id) local url = string.format('appearance/wear-user-outfit?id=%d', id) return rbxApiPostAsync(url, '', false) end function Http.PostWearAssetAsync(assetId) --local BaseUrl = 'http://api.gametest5.watrbx.local/' return rbxApiPostAsync('appearance/set-clothing?assetIds='..tostring(assetId), '', false) end -- @ Params -- productId - integer number of the id of the product (different from assetId) -- expectedPrice - integer for how much of the currency is required to purchase -- expectedSellerId - UserId integer for the seller of the product -- expectedCurrency - integer denoting whether the currency is robux or tickets -- 1 = robux -- @ Example result is a table: -- balanceAfterSale 197620 -- sl_translate title, errorMsg -- AssetID 86500185 -- shortfallPrice -197620 -- errorMsg You already own this item. -- statusCode 500 -- title Item Owned -- currentPrice 25 -- expectedPrice 25 -- showDivID TransactionFailureView -- expectedCurrency 1 -- currentCurrency 1 function Http.PurchaseProductAsync(productId, expectedPrice, expectedSellerId, expectedCurrency) -- local formattedUrl = BaseUrl .. 'API/Item.ashx?rqtype=purchase' .. -- '&productID=' .. tostring(productId) .. -- '&expectedCurrency=' .. tostring(expectedCurrency) .. -- '&expectedPrice=' .. tostring(expectedPrice) .. -- '&expectedSellerID=' .. tostring(expectedSellerId) local formattedUrl = string.format('%sAPI/Item.ashx?rqtype=purchase&productID=%d&expectedCurrency=%d&expectedPrice=%d&expectedSellerID=%d', BaseUrl, productId, expectedCurrency, expectedPrice, expectedSellerId) print('PurchaseProductAsync:' , formattedUrl) return rbxPostAsync(formattedUrl, '') -- path, params, contentType) -- return http://www.watrbx.wtf/API/Item.ashx?rqtype=purchase&productID=24805065&expectedCurrency=1&expectedPrice=88&expectedSellerID=1 end -- Sample response: --[=[ {Products = {{AssetTypeId = 32, IconImageAssetId = 0, IsNew = false, Updated = '2015-08-03T22:26:25.447Z', IsLimitedUnique = false, ProductId = 9187002, MinimumMembershipLevel = 1, Created = '2011-08-05T21:50:20.67Z', Creator = {Name = 'ROBLOX', Id = 1}, IsLimited = false, ContentRatingTypeId = 0, AssetId = 58537634, IsPublicDomain = false, Name = 'Knight of the Splintered Sky', IsForSale = true, Description = 'He fights bravely along side his brothers and the Knights of Redcliff to defeat the evil Korblox and their zombies.', PriceInRobux = 1000, Sales = 19}}} --]=] function Http.GetXboxProductsAsync(startIndex, count) startIndex = startIndex or 0 count = count or 20 local url = string.format('xbox/catalog/contents?startIndex=%d&count=%d', startIndex, count) return rbxApiGetAsync(url, true) end function Http.GetXboxCurrentlyWearingPackageAsync() local url = string.format('xbox/currently-wearing') return rbxApiGetAsync(url, true) end ----- function Http.GetThumbnailUrlForAsset(assetId, width, height) width = width or 420 height = height or 420 return AssetGameBaseUrl .. 'Thumbs/Asset.ashx?width='..tostring(width)..'&height='..tostring(height)..'&assetId='..tostring(assetId) end -- Report Abuse function Http.ReportAbuseAsync(reportingItemTypeName, reportingItemId, reportCategoryId, comment) local jsonPostBody = { reportingItemTypeName = reportingItemTypeName; reportingItemId = tostring(reportingItemId); reportCategoryId = tostring(reportCategoryId); comment = comment; } local params = HttpService:JSONEncode(jsonPostBody) if params then return rbxApiPostAsync('moderation/reportabuse', params, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationJson) end end --- Achievements function Http.GetConsecutiveDaysLoggedInAsync() local url = string.format('/xbox/get-login-consecutive-days') return rbxApiGetAsync(url, true) end function Http.GetVoteCountAsync() local url = string.format('/user/get-vote-count?targetType=Place') return rbxApiGetAsync(url, true) end -- Account Linking --[[ // Returns table // Table Keys // IsValid - boolean // ErrorMessage - string ]] function Http.IsValidUsername(username) return rbxApiGetAsync('signup/is-username-valid?username='..username, true) end --[[ // Returns table // Table Keys // IsValid - boolean // ErrorMessage - string ]] function Http.IsValidPassword(username, password) return rbxApiGetAsync('signup/is-password-valid?username='..username..'&password='..password, true) end return Http