Skip to content

Instantly share code, notes, and snippets.

@pirica
Forked from Amrsatrio/AccountService.java
Created June 22, 2021 03:04
Show Gist options
  • Select an option

  • Save pirica/7710e9d7614b6304a7f00e54c743684a to your computer and use it in GitHub Desktop.

Select an option

Save pirica/7710e9d7614b6304a7f00e54c743684a to your computer and use it in GitHub Desktop.

Revisions

  1. @Amrsatrio Amrsatrio revised this gist Apr 28, 2021. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions FulfillmentService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,17 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.RedeemCodePayload;
    import com.tb24.fn.model.RedeemCodeResponse;
    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.POST;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface FulfillmentService {
    String BASE_URL_PROD = "https://fulfillment-public-service-prod.ol.epicgames.com/fulfillment/";
    String BASE_URL_STAGE = "https://fulfillment-public-service-stage.ol.epicgames.com/fulfillment/";

    @POST("api/public/accounts/{accountId}/codes/{codeId}")
    Call<RedeemCodeResponse> redeemCode(@Path("accountId") String accountId, @Path("codeId") String codeId, @Query("codeUseId") String codeUseId, @Body RedeemCodePayload payload);
    }
  2. @Amrsatrio Amrsatrio revised this gist Apr 28, 2021. 13 changed files with 294 additions and 119 deletions.
    119 changes: 60 additions & 59 deletions AccountService.java
    Original file line number Diff line number Diff line change
    @@ -1,109 +1,110 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonObject;
    import com.tb24.fn.model.DeviceAuth;
    import com.tb24.fn.model.ExchangeResponse;
    import com.tb24.fn.model.ExternalAuth;
    import com.tb24.fn.model.GameProfile;
    import com.tb24.fn.model.LoginResponse;
    import com.tb24.fn.model.QueryExternalIdMappingsByIdPayload;
    import com.tb24.fn.model.VerifyResponse;
    import com.tb24.fn.model.XGameProfile;
    import com.tb24.fn.model.account.*;
    import retrofit2.Call;
    import retrofit2.http.*;

    import java.util.List;
    import java.util.Map;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.Field;
    import retrofit2.http.FieldMap;
    import retrofit2.http.FormUrlEncoded;
    import retrofit2.http.GET;
    import retrofit2.http.Header;
    import retrofit2.http.POST;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface AccountService {
    String BASE_URL_PROD = "https://account-public-service-prod.ol.epicgames.com/account/";
    String BASE_URL_PROD_ALT = "https://account-public-service-prod.ak.epicgames.com/account/";
    String BASE_URL_STAGE = "https://account-public-service-stage.ol.epicgames.com/account/";

    @GET("api/oauth/verify")
    Call<VerifyResponse> verify(@Query("includePerms") Boolean includePerms);

    /**
    * grant_type: authorization_code; fields: code
    * grant_type: client_credentials
    * grant_type: device_auth; fields: account_id, device_id, secret
    * grant_type: exchange_code; fields: exchange_code
    * grant_type: external_auth; fields: external_auth_type, external_auth_token
    * grant_type: otp; fields: otp, challenge
    * grant_type: password; fields: username, password
    * grant_type: refresh_token; fields: refresh_token
    * <pre>
    * grant_type fields
    * ------------------------------------------------------------
    * authorization_code code
    * client_credentials -
    * device_auth account_id, device_id, secret
    * device_code device_code
    * exchange_code exchange_code
    * external_auth external_auth_type, external_auth_token
    * otp otp, challenge
    * password username, password
    * refresh_token refresh_token
    * token_to_token access_token
    * </pre>
    */
    @FormUrlEncoded
    @POST("api/oauth/token")
    Call<LoginResponse> grantToken(@Header("Authorization") String auth, @Field("grant_type") String grantType, @FieldMap Map<String, String> fields, @Field("includePerms") Boolean includePerms);
    @FormUrlEncoded
    Call<Token> getAccessToken(@Header("Authorization") String auth, @Field("grant_type") String grantType, @FieldMap Map<String, String> fields, @Field("includePerms") Boolean includePerms);

    @GET("api/oauth/exchange")
    Call<ExchangeResponse> generateExchangeCode();

    @GET("api/oauth/verify")
    Call<VerifyResponse> verifyToken(@Query("includePerms") Boolean includePerms);

    @DELETE("api/oauth/sessions/kill/{accessToken}")
    Call<Void> killAuthSession(@Path("accessToken") String accessToken);
    Call<ExchangeResponse> getExchangeCode();

    /**
    * @param killType OTHERS, ALL_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT_SERVICE
    */
    @DELETE("api/oauth/sessions/kill")
    Call<Void> killAuthSessions(@Query("killType") String killType);
    Call<Void> killSessions(@Query("killType") String killType);

    @DELETE("api/oauth/sessions/kill/{accessToken}")
    Call<Void> killSession(@Path("accessToken") String accessToken);

    @POST("api/oauth/deviceAuthorization")
    @FormUrlEncoded
    Call<PinGrantInfo> initiatePinAuth(@Field("prompt") String prompt);

    @DELETE("api/oauth/deviceAuthorization/{userCode}")
    Call<Void> cancelPinAuth(@Path("userCode") String userCode);

    @POST("api/public/account")
    Call<AccountMutationResponse> createAccount(@Query("authenticate") Boolean authenticate, @Query("tokenType") String tokenType, @Query("sendEmail") Boolean sendEmail, @Body AccountMutationPayload payload);

    @GET("api/public/account")
    Call<GameProfile[]> queryUserInfo(@Query("accountId") List<String> ids);
    Call<GameProfile[]> findAccountsByIds(@Query("accountId") List<String> accountIds);

    @GET("api/public/account/{accountId}")
    Call<XGameProfile> getById(@Path("accountId") String accountId);

    @GET("api/public/account/{id}")
    Call<XGameProfile> queryUserInfo(@Path("id") String id);
    @PUT("api/public/account/{accountId}")
    Call<AccountMutationResponse> editAccountDetails(@Path("accountId") String accountId, @Body AccountMutationPayload payload);

    @GET("api/accounts/{id}/metadata")
    Call<JsonObject> queryUserMetaData(@Path("id") String id);
    @GET("api/accounts/{accountId}/metadata")
    Call<JsonObject> getAccountMetadata(@Path("accountId") String accountId);

    @GET("api/public/account/{accountId}/deviceAuth")
    Call<DeviceAuth[]> queryDeviceAuths(@Path("accountId") String accountId);
    Call<DeviceAuth[]> getDeviceAuths(@Path("accountId") String accountId);

    @GET("api/public/account/{accountId}/deviceAuth/{deviceId}")
    Call<DeviceAuth> queryDeviceAuths(@Path("accountId") String accountId, @Path("deviceId") String deviceId);
    Call<DeviceAuth> getDeviceAuth(@Path("accountId") String accountId, @Path("deviceId") String deviceId);

    @POST("api/public/account/{accountId}/deviceAuth")
    Call<DeviceAuth> createDeviceAuth(@Path("accountId") String accountId, @Header("X-Epic-Device-Info") String deviceInfo);

    @DELETE("api/public/account/{accountId}/deviceAuth/{deviceId}")
    Call<Void> deleteDeviceAuth(@Path("accountId") String accountId, @Path("deviceId") String deviceId);

    @GET("api/public/account/{id}/externalAuths")
    Call<ExternalAuth[]> queryExternalAccounts(@Path("id") String id);
    @GET("api/public/account/{accountId}/externalAuths")
    Call<ExternalAuth[]> getExternalAuths(@Path("accountId") String accountId);

    @GET("api/public/account/{id}/externalAuths/{type}")
    Call<ExternalAuth> queryExternalAccountsByType(@Path("id") String id, @Path("type") String type);
    @GET("api/public/account/{accountId}/externalAuths/{type}")
    Call<ExternalAuth> getExternalAuth(@Path("accountId") String accountId, @Path("type") String type);

    // TODO @POST("api/public/account/{id}/externalAuths")
    // JsonObject: authType, externalAuthToken
    // Call<ExternalAuth[]> addExternalAccount(@Path("id") String id, @Body AddExternalAccountPayload payload);
    @POST("api/public/account/{accountId}/externalAuths")
    Call<ExternalAuth> createExternalAuth(@Path("accountId") String accountId, @Body AddExternalAuthPayload payload);

    @DELETE("api/public/account/{id}/externalAuths/{type}")
    Call<Void> removeExternalAccount(@Path("id") String id, @Path("type") String type);
    @DELETE("api/public/account/{accountId}/externalAuths/{type}")
    Call<Void> removeExternalAuth(@Path("accountId") String accountId, @Path("type") String type);

    @GET("api/public/account/displayName/{name}")
    Call<GameProfile> queryUserIdFromDisplayName(@Path("name") String name);
    @GET("api/public/account/displayName/{displayName}")
    Call<GameProfile> getByDisplayName(@Path("displayName") String displayName);

    @GET("api/public/account/email/{email}")
    Call<GameProfile> queryUserIdFromEmail(@Path("email") String email);
    Call<GameProfile> getByEmail(@Path("email") String email);

    @POST("api/public/account/lookup/externalId")
    Call<Map<String, ExternalAuth>> queryExternalIdMappingsById(@Body QueryExternalIdMappingsByIdPayload payload);
    Call<Map<String, ExternalAuth>> getExternalIdMappingsById(@Body QueryExternalIdMappingsByIdPayload payload);

    @GET("api/public/account/lookup/externalAuth/{externalAuthType}/displayName/{displayName}")
    Call<GameProfile[]> queryExternalIdMappingsByDisplayName(@Path("externalAuthType") String externalAuthType, @Path("displayName") String displayName, @Query("caseInsensitive") Boolean caseInsensitive);
    Call<GameProfile[]> getExternalIdMappingsByDisplayName(@Path("externalAuthType") EExternalAuthType externalAuthType, @Path("displayName") String displayName, @Query("caseInsensitive") Boolean caseInsensitive);

    @GET("api/epicdomains/ssodomains")
    Call<String[]> querySSODomains();
    31 changes: 13 additions & 18 deletions CatalogService.java
    Original file line number Diff line number Diff line change
    @@ -1,46 +1,41 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.tb24.fn.model.EpicGraphQLTypes;
    import com.tb24.fn.model.Paged;

    import java.util.List;
    import java.util.Map;

    import com.tb24.fn.model.catalog.Currency;
    import com.tb24.fn.model.catalog.StoreItem;
    import com.tb24.fn.model.catalog.StoreOffer;
    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    import java.util.List;
    import java.util.Map;

    public interface CatalogService {
    String BASE_URL_PROD = "https://catalog-public-service-prod06.ol.epicgames.com/catalog/";
    String BASE_URL_PROD_ALT = "https://catalog-public-service-prod06.ak.epicgames.com/catalog/";
    String BASE_URL_STAGE = "https://catalogv2-public-service-stage.ol.epicgames.com/catalog/";

    // TODO research
    @GET("api/shared/categories")
    Call<JsonElement> queryCategories();

    @GET("api/shared/currencies")
    Call<Paged<EpicGraphQLTypes.Currency>> queryCurrencies(@Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<Currency>> queryCurrencies(@Query("start") Integer start, @Query("count") Integer count);

    @GET("api/shared/namespace/{namespace}/items")
    Call<Paged<EpicGraphQLTypes.CatalogItem>> queryItems(@Path("namespace") String namespace, @Query("includeDLCDetails") Boolean includeDLCDetails, @Query("includeMainGameDetails") Boolean includeMainGameDetails, @Query("status") String status, @Query("sortBy") String sortBy, @Query("country") String country, @Query("locale") String locale, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<StoreItem>> queryItems(@Path("namespace") String namespace, @Query("includeDLCDetails") Boolean includeDLCDetails, @Query("includeMainGameDetails") Boolean includeMainGameDetails, @Query("status") String status, @Query("sortBy") String sortBy, @Query("country") String country, @Query("locale") String locale, @Query("start") Integer start, @Query("count") Integer count);

    @GET("api/shared/namespace/{namespace}/offers")
    Call<Paged<EpicGraphQLTypes.CatalogOffer>> queryOffers(@Path("namespace") String namespace, @Query("status") String status, /* Maybe */ @Query("country") String country, @Query("locale") String locale, @Query("start") Integer start, @Query("count") Integer count, @Query("returnItemDetails") Boolean returnItemDetails);
    Call<Paged<StoreOffer>> queryOffers(@Path("namespace") String namespace, @Query("status") String status, /* Maybe */ @Query("country") String country, @Query("locale") String locale, @Query("start") Integer start, @Query("count") Integer count, @Query("returnItemDetails") Boolean returnItemDetails);

    // TODO research
    @GET("api/shared/bulk/items")
    Call<Map<String, EpicGraphQLTypes.CatalogItem>> queryItemsBulk();
    Call<Map<String, StoreItem>> queryItemsBulk(@Query("id") List<String> ids, @Query("includeDLCDetails") Boolean includeDLCDetails, @Query("includeMainGameDetails") Boolean includeMainGameDetails, @Query("country") String country, @Query("locale") String locale);

    // Used in Fortnite
    @GET("api/shared/bulk/offers")
    Call<Map<String, EpicGraphQLTypes.CatalogOffer>> queryOffersBulk(@Query("id") List<String> ids, @Query("returnItemDetails") Boolean returnItemDetails, @Query("country") String country, @Query("locale") String locale);
    Call<Map<String, StoreOffer>> queryOffersBulk(@Query("id") List<String> ids, @Query("returnItemDetails") Boolean returnItemDetails, @Query("country") String country, @Query("locale") String locale);

    @GET("api/shared/namespace/{namespace}/bulk/items")
    Call<Map<String, EpicGraphQLTypes.CatalogItem>> queryItemsBulkNamespace(@Path("namespace") String namespace, List<String> ids, @Query("includeDLCDetails") Boolean includeDLCDetails, @Query("includeMainGameDetails") Boolean includeMainGameDetails, @Query("country") String country, @Query("locale") String locale);
    Call<Map<String, StoreItem>> queryItemsBulkNamespace(@Path("namespace") String namespace, @Query("id") List<String> ids, @Query("includeDLCDetails") Boolean includeDLCDetails, @Query("includeMainGameDetails") Boolean includeMainGameDetails, @Query("country") String country, @Query("locale") String locale);

    @GET("api/shared/namespace/{namespace}/bulk/offers")
    Call<Map<String, EpicGraphQLTypes.CatalogOffer>> queryOffersBulkNamespace(@Path("namespace") String namespace);
    Call<Map<String, StoreOffer>> queryOffersBulkNamespace(@Path("namespace") String namespace, @Query("id") List<String> ids, @Query("returnItemDetails") Boolean returnItemDetails, @Query("country") String country, @Query("locale") String locale);
    }
    18 changes: 18 additions & 0 deletions CodeRedemptionService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,18 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.coderedemption.EvaluateCodeResponse;
    import com.tb24.fn.model.coderedemption.LockCodeResponse;
    import retrofit2.Call;
    import retrofit2.http.POST;
    import retrofit2.http.Path;

    public interface CodeRedemptionService {
    String BASE_URL_PROD = "https://coderedemption-public-service-prod.ol.epicgames.com/coderedemption/";
    String BASE_URL_STAGE = "https://coderedemption-public-service-stage.ol.epicgames.com/coderedemption/";

    @POST("api/shared/code/{codeId}/lock")
    Call<LockCodeResponse> lockCode(@Path("codeId") String codeId);

    @POST("api/shared/accounts/{accountId}/redeem/{codeId}/evaluate")
    Call<EvaluateCodeResponse> evaluateCode(@Path("accountId") String accountId, @Path("codeId") String codeId);
    }
    14 changes: 9 additions & 5 deletions EventsService.java
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,10 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.tb24.fn.model.AccountCompetitiveData;
    import com.tb24.fn.model.EventDownloadResponse;
    import com.tb24.fn.model.LeaderboardsResponse;

    import com.google.gson.JsonObject;
    import com.tb24.fn.model.events.AccountCompetitiveData;
    import com.tb24.fn.model.events.EventDownloadResponse;
    import com.tb24.fn.model.events.LeaderboardsResponse;
    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Path;
    @@ -35,9 +35,10 @@ public interface EventsService {
    * @param accountId "00112233445566778899aabbccddeeff"
    * @param regionId "ASIA"
    * @param bShowPastEvents ???
    * @param bShowPrivateEvents ???
    */
    @GET("api/v1/events/{GameId}/data/{AccountId}")
    Call<JsonElement> data(@Path("GameId") String gameId, @Path("AccountId") String accountId, @Query("region") String regionId, @Query("showPastEvents") Boolean bShowPastEvents);
    Call<JsonElement> data(@Path("GameId") String gameId, @Path("AccountId") String accountId, @Query("region") String regionId, @Query("showPastEvents") Boolean bShowPastEvents, @Query("showPrivateEvents") Boolean bShowPrivateEvents);

    /**
    * TODO haven't tried
    @@ -90,4 +91,7 @@ public interface EventsService {
    */
    @GET("api/v1/events/{GameId}/{EventId}/{EventWindowId}/history/{AccountId}")
    Call<JsonElement[]> eventWindowHistoryForAccount(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("EventWindowId") String eventWindowId, @Path("AccountId") String accountId);

    @GET("api/v1/players/{GameId}/tokens")
    Call<JsonObject> tokens(@Path("GameId") String gameId, @Query("teamAccountIds") String accountIds);
    }
    60 changes: 37 additions & 23 deletions FortniteService.java
    Original file line number Diff line number Diff line change
    @@ -1,37 +1,36 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.tb24.fn.model.AccountPrivacyResponse;
    import com.tb24.fn.model.CalendarTimelineResponse;
    import com.tb24.fn.model.CloudStorageFile;
    import com.tb24.fn.model.CloudStorageUsageInfo;
    import com.tb24.fn.model.FortCatalogResponse;
    import com.tb24.fn.model.LinkEntry;
    import com.tb24.fn.model.LinksQueryResponse;
    import com.tb24.fn.model.Receipt;
    import com.tb24.fn.model.WorldInfoResponse;
    import com.tb24.fn.model.InventorySnapshotResponse;
    import com.tb24.fn.model.MatchmakingTicketResponse;
    import com.tb24.fn.model.cloudstorage.CloudStorageFile;
    import com.tb24.fn.model.cloudstorage.CloudStorageUsageInfo;
    import com.tb24.fn.model.gamesubcatalog.CatalogDownload;
    import com.tb24.fn.model.gamesubcatalog.CatalogReceiptInfo;
    import com.tb24.fn.model.links.LinkEntry;
    import com.tb24.fn.model.links.LinksQueryResponse;
    import com.tb24.fn.model.mcpprofile.ProfileUpdate;

    import com.tb24.fn.model.scheduledevents.CalendarDownload;
    import okhttp3.RequestBody;
    import okhttp3.ResponseBody;
    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.Header;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;
    import retrofit2.http.*;

    import java.util.Map;

    public interface FortniteService {
    String BASE_URL = "https://fortnite-public-service-prod11.ol.epicgames.com/fortnite/";

    @POST("api/game/v2/profile/{id}/client/{command}")
    Call<ProfileUpdate> clientCommand(@Path("command") String command, @Path("id") String accountId, @Query("profileId") String profileId, @Query("rvn") Long currentProfileRevision, @Header("X-EpicGames-ProfileRevisions") String profileRevisionsMeta, @Body Object payload);

    @POST("api/game/v2/profile/{id}/public/{command}")
    Call<ProfileUpdate> publicCommand(@Path("command") String command, @Path("id") String accountId, @Query("profileId") String profileId, @Query("rvn") Long currentProfileRevision, @Header("X-EpicGames-ProfileRevisions") String profileRevisionsMeta, @Body Object payload);

    @GET("api/game/v2/world/info")
    Call<WorldInfoResponse> queryTheaterList(@Header("X-EpicGames-Language") String language);
    Call<ResponseBody> queryTheaterList(@Header("X-EpicGames-Language") String language);

    @GET("api/game/v2/privacy/account/{id}")
    Call<AccountPrivacyResponse> getAccountPrivacy(@Path("id") String id);
    @@ -40,10 +39,10 @@ public interface FortniteService {
    Call<AccountPrivacyResponse> setAccountPrivacy(@Path("id") String id, @Body AccountPrivacyResponse payload);

    @GET("api/storefront/v2/catalog")
    Call<FortCatalogResponse> storefrontCatalog(@Header("X-EpicGames-Language") String language);
    Call<CatalogDownload> storefrontCatalog(@Header("X-EpicGames-Language") String language);

    @GET("api/calendar/v1/timeline")
    Call<CalendarTimelineResponse> calendarTimeline();
    Call<CalendarDownload> calendarTimeline();

    @GET("api/cloudstorage/system")
    Call<CloudStorageFile[]> enumerateTitleFiles();
    @@ -67,10 +66,10 @@ public interface FortniteService {
    Call<CloudStorageUsageInfo> requestUsageInfo(@Path("id") String accountId);

    @POST("api/game/v2/events/v2/processPendingRewards/{id}")
    Call<String[]> eventsProcessPendingRewards(@Path("id") String id);
    Call<String[]> processPendingRewards(@Path("id") String id);

    /**
    * @param platform PC, MOBILE, PS4, XBOX_ONE, or SWITCH
    * platform PC, MOBILE, PS4, XBOX_ONE, or SWITCH
    */
    @POST("api/game/v2/tryPlayOnPlatform/account/{id}")
    Call<Boolean> checkPlatformPlayAllowed(@Path("id") String id, @Query("platform") String platform);
    @@ -85,7 +84,16 @@ public interface FortniteService {
    Call<String[]> storefrontKeychain(@Query("numKeysDownloaded") Integer numKeysDownloaded);

    @GET("api/receipts/v1/account/{id}/receipts")
    Call<Receipt[]> receipts(@Path("id") String id);
    Call<CatalogReceiptInfo[]> receipts(@Path("id") String id);

    //@POST("api/storeaccess/v1/redeem_access/{id}")
    //Call<Void> redeemAccess(@Path("id") String id); // requires payload, unknown

    @POST("api/storeaccess/v1/request_access/{id}")
    Call<Void> requestAccess(@Path("id") String id);

    @POST("api/accesscontrol/status")
    Call<JsonObject> checkAccess(); // { play: boolean, isBanned: boolean }

    /**
    * @param olderThan in ISO 8601 date format
    @@ -116,4 +124,10 @@ public interface FortniteService {

    @GET("api/storefront/v2/gift/check_eligibility/recipient/{recipientAccountId}/offer/{offerId}")
    Call<Void> checkGiftEligibility(@Path("recipientAccountId") String recipientAccountId, @Path("offerId") String offerId);

    @GET("api/game/v2/br-inventory/account/{accountId}")
    Call<InventorySnapshotResponse> inventorySnapshot(@Path("accountId") String accountId);

    @GET("api/game/v2/matchmakingservice/ticket/player/{accountId}")
    Call<MatchmakingTicketResponse> mmsObtainTicket(@Path("accountId") String accountId, @QueryMap Map<String, String> params);
    }
    17 changes: 3 additions & 14 deletions FriendsService.java
    Original file line number Diff line number Diff line change
    @@ -1,29 +1,18 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonObject;
    import com.tb24.fn.model.BlockedUsers;
    import com.tb24.fn.model.Friend;
    import com.tb24.fn.model.FriendV2;
    import com.tb24.fn.model.FriendsSettings;
    import com.tb24.fn.model.FriendsV2Summary;

    import com.tb24.fn.model.friends.*;
    import okhttp3.RequestBody;
    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;
    import retrofit2.http.*;

    public interface FriendsService {
    String BASE_URL_PROD = "https://friends-public-service-prod.ol.epicgames.com/friends/";
    String BASE_URL_PROD_ALT = "https://friends-public-service-prod.ak.epicgames.com/friends/";
    String BASE_URL_STAGE = "https://friends-public-service-stage.ol.epicgames.com/friends/";

    @GET("api/v1/{id}/summary")
    Call<FriendsV2Summary> queryFriendsSummary(@Path("id") String id, @Query("displayNames") Boolean displayNames);
    Call<FriendsSummary> queryFriendsSummary(@Path("id") String id, @Query("displayNames") Boolean displayNames);

    @GET("api/v1/{id}/friends")
    Call<FriendV2[]> queryFriends(@Path("id") String id, @Query("displayNames") Boolean displayNames);
    14 changes: 14 additions & 0 deletions InteractionsService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.interactions.LastInteractionsResponse;
    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Path;

    public interface InteractionsService {
    String BASE_URL_PROD = "https://interactions-service-prod.ol.epicgames.com/";
    String BASE_URL_STAGE = "https://interactions-service-stage.ol.epicgames.com/";

    @GET("api/v1/{namespace}/get")
    Call<LastInteractionsResponse> queryLastInteractions(@Path("namespace") String namespace);
    }
    16 changes: 16 additions & 0 deletions LauncherService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.launcher.BuildResponse;
    import com.tb24.fn.model.launcher.ClientDetails;
    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.POST;
    import retrofit2.http.Path;

    public interface LauncherService {
    String BASE_URL_PROD = "https://launcher-public-service-prod06.ol.epicgames.com/launcher/";
    String BASE_URL_STAGE = "https://launcher-public-service-stage.ol.epicgames.com/launcher/";

    @POST("api/public/assets/v2/platform/{platform}/catalogItem/{catalogItemId}/app/{appName}/label/{label}")
    Call<BuildResponse> querySignedDownload(@Path("platform") String platform, @Path("catalogItemId") String catalogItemId, @Path("appName") String appName, @Path("label") String label, @Body ClientDetails clientDetails);
    }
    30 changes: 30 additions & 0 deletions LibraryService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.library.LibraryItems;
    import com.tb24.fn.model.library.Playtime;
    import com.tb24.fn.model.library.PlaytimeAddList;
    import com.tb24.fn.model.library.PlaytimePayload;
    import retrofit2.Call;
    import retrofit2.http.*;

    public interface LibraryService {
    String BASE_URL = "https://library-service.live.use1a.on.epicgames.com/library/";

    @PUT("api/public/playtime/account/{accountId}")
    Call<Void> sendPlaytime(@Path("accountId") String accountId, @Body PlaytimePayload payload);

    @PUT("api/public/playtime/account/{accountId}/bulk")
    Call<Void> sendPlaytimeBulk(@Path("accountId") String accountId, @Body PlaytimeAddList payload);

    @GET("api/public/playtime/account/{accountId}/artifact/{artifactId}")
    Call<Playtime> queryPlaytime(@Path("accountId") String accountId, @Path("artifactId") String artifactId);

    @GET("api/public/playtime/account/{accountId}/all")
    Call<Playtime[]> queryAllPlaytime(@Path("accountId") String accountId);

    //@GET("api/public/items/hwid/{hardwareId}")
    //Call<Void> queryAntiPiracyTokens(@Path("hardwareId") String hardwareId, @Query("platform") String platform);

    @GET("api/public/items")
    Call<LibraryItems> queryItems(@Query("includeMetadata") Boolean includeMetadata, @Query("cursor") String cursor, @Query("excludeNs") String... excludeNs);
    }
    15 changes: 15 additions & 0 deletions LightswitchService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.lightswitch.ServiceStatus;
    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Query;

    public interface LightswitchService {
    String BASE_URL_PROD = "https://lightswitch-public-service-prod.ol.epicgames.com/lightswitch/";
    String BASE_URL_PROD_ALT = "https://lightswitch-public-service-prod.ak.epicgames.com/lightswitch/";
    String BASE_URL_STAGE = "https://lightswitch-public-service-stage.ol.epicgames.com/lightswitch/";

    @GET("api/service/bulk/status")
    Call<ServiceStatus[]> queryServiceStatus(@Query("serviceId") String... serviceIds);
    }
    22 changes: 22 additions & 0 deletions LinksService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.links.LinkData;
    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface LinksService {
    String BASE_URL_LIVE = "https://links-public-service-live.ol.epicgames.com/links/";
    String BASE_URL_PROD = "https://links-public-service-prod.ol.epicgames.com/links/";
    String BASE_URL_STAGE = "https://links-public-service-stage.ol.epicgames.com/links/";

    @GET("api/{namespace}/mnemonic/{mnemonic}")
    Call<LinkData> queryLinkByMnemonic(@Path("namespace") String namespace, @Path("mnemonic") String mnemonic, @Query("type") String type, @Query("v") Integer version);

    /*@GET("api/{namespace}/author/{accountId}")
    Call<ResponseBody> queryLinksByAccount(@Path("namespace") String namespace, @Path("accountId") String accountId);
    @POST("api/{namespace}/author/{accountId}")
    Call<ResponseBody> createLink(@Path("namespace") String namespace, @Path("accountId") String accountId);*/
    }
    42 changes: 42 additions & 0 deletions PresenceService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.presence.LastOnline;
    import com.tb24.fn.model.presence.NudgedSubscription;
    import com.tb24.fn.model.presence.Subscription;
    import com.tb24.fn.model.presence.SubscriptionSettings;
    import retrofit2.Call;
    import retrofit2.http.*;

    import java.util.Map;

    public interface PresenceService {
    String BASE_URL_PROD = "https://presence-public-service-prod.ol.epicgames.com/presence/";
    String BASE_URL_STAGE = "https://presence-public-service-stage.ol.epicgames.com/presence/";

    @GET("api/v1/_/{id}/last-online")
    Call<Map<String, LastOnline[]>> queryLastOnline(@Path("id") String id);

    @GET("api/v1/_/{id}/settings/subscriptions")
    Call<SubscriptionSettings> querySubscriptionSettings(@Path("id") String id);

    @PATCH("api/v1/_/{id}/settings/subscriptions")
    Call<Void> updateSubscriptionSettings(@Path("id") String id, @Body SubscriptionSettings payload);

    @POST("api/v1/_/{id}/subscriptions/{otherId}")
    Call<Void> subscribe(@Path("id") String id);

    @DELETE("api/v1/_/{id}/subscriptions/{otherId}")
    Call<Void> unsubscribe(@Path("id") String id);

    @GET("api/v1/_/{id}/subscriptions")
    Call<Subscription[]> querySubscriptions(@Path("id") String id);

    @POST("api/v1/{namespace}/{id}/subscriptions/broadcast")
    Call<Void> broadcastSubscription(@Path("id") String id);

    @PUT("api/v1/{namespace}/{id}/subscriptions/nudged/{otherId}")
    Call<Void> sendSubscriptionNudge(@Path("namespace") String namespace, @Path("id") String id, @Path("otherId") String otherId);

    @GET("api/v1/{namespace}/{id}/subscriptions/nudged")
    Call<NudgedSubscription[]> queryNudgedSubscriptions(@Path("namespace") String namespace, @Path("id") String id);
    }
    15 changes: 15 additions & 0 deletions UserSearchService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.UserSearchResultEntry;
    import com.tb24.fn.model.account.EExternalAuthType;
    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Query;

    public interface UserSearchService {
    String BASE_URL_PROD = "https://user-search-service-prod.ol.epicgames.com/";
    String BASE_URL_STAGE = "https://user-search-service-stage.ol.epicgames.com/";

    @GET("api/v1/search")
    Call<UserSearchResultEntry[]> queryUsers(@Query("prefix") String prefix, @Query("platform") EExternalAuthType platform);
    }
  3. @Amrsatrio Amrsatrio revised this gist Dec 9, 2020. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions FortniteService.java
    Original file line number Diff line number Diff line change
    @@ -6,11 +6,11 @@
    import com.tb24.fn.model.CloudStorageFile;
    import com.tb24.fn.model.CloudStorageUsageInfo;
    import com.tb24.fn.model.FortCatalogResponse;
    import com.tb24.fn.model.FortMcpResponse;
    import com.tb24.fn.model.LinkEntry;
    import com.tb24.fn.model.LinksQueryResponse;
    import com.tb24.fn.model.Receipt;
    import com.tb24.fn.model.WorldInfoResponse;
    import com.tb24.fn.model.mcpprofile.ProfileUpdate;

    import okhttp3.RequestBody;
    import okhttp3.ResponseBody;
    @@ -28,7 +28,7 @@ public interface FortniteService {
    String BASE_URL = "https://fortnite-public-service-prod11.ol.epicgames.com/fortnite/";

    @POST("api/game/v2/profile/{id}/client/{command}")
    Call<FortMcpResponse> clientCommand(@Path("command") String command, @Path("id") String accountId, @Query("profileId") String profileId, @Query("rvn") Integer currentProfileRevision, @Header("X-EpicGames-ProfileRevisions") String profileRevisionsMeta, @Body Object payload);
    Call<ProfileUpdate> clientCommand(@Path("command") String command, @Path("id") String accountId, @Query("profileId") String profileId, @Query("rvn") Long currentProfileRevision, @Header("X-EpicGames-ProfileRevisions") String profileRevisionsMeta, @Body Object payload);

    @GET("api/game/v2/world/info")
    Call<WorldInfoResponse> queryTheaterList(@Header("X-EpicGames-Language") String language);
    @@ -67,7 +67,7 @@ public interface FortniteService {
    Call<CloudStorageUsageInfo> requestUsageInfo(@Path("id") String accountId);

    @POST("api/game/v2/events/v2/processPendingRewards/{id}")
    Call<JsonElement[]> eventsProcessPendingRewards(@Path("id") String id);
    Call<String[]> eventsProcessPendingRewards(@Path("id") String id);

    /**
    * @param platform PC, MOBILE, PS4, XBOX_ONE, or SWITCH
  4. @Amrsatrio Amrsatrio revised this gist Jan 19, 2020. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions ChannelsService.java
    Original file line number Diff line number Diff line change
    @@ -10,6 +10,7 @@
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.Field;
    import retrofit2.http.FormUrlEncoded;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    @@ -79,12 +80,14 @@ public interface ChannelsService {
    Call<UserSetting[]> QueryMultiUserSingleSetting(@Query("accountId") List<String> accountIds, @Path("settingKey") String settingKey);

    @POST("api/v1/user/setting/{settingKey}")
    @FormUrlEncoded
    Call<UserSetting[]> QueryMultiUserSingleSetting_Field(@Field("accountId") List<String> accountIds, @Path("settingKey") String settingKey);

    @GET("api/v1/user/setting")
    Call<UserSetting[]> QueryMultiUserMultiSetting(@Query("accountId") List<String> accountIds, @Query("settingKey") List<String> settingKeys);

    @POST("api/v1/user/setting")
    @FormUrlEncoded
    Call<UserSetting[]> QueryMultiUserMultiSetting_Field(@Field("accountId") List<String> accountIds, @Field("settingKey") List<String> settingKeys);

    // TODO Unknown method, cannot be tested
  5. @Amrsatrio Amrsatrio revised this gist Jan 18, 2020. 1 changed file with 22 additions and 11 deletions.
    33 changes: 22 additions & 11 deletions GroupsService.java
    Original file line number Diff line number Diff line change
    @@ -16,18 +16,22 @@
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.Headers;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    /**
    * Page count of paginated responses here is 50.
    */
    public interface GroupsService {
    String BASE_URL_PROD = "https://groups-service-prod06.ol.epicgames.com/groups/";
    String BASE_URL_PROD_ALT = "https://groups-service-prod.ak.epicgames.com/groups/";
    String BASE_URL_PROD_STAGE = "https://groups-service-stage.ol.epicgames.com/groups/";

    @GET("api/v1/groups/in/{ns}")
    Call<Paged<Group>> FindGroups(@Path("ns") String ns, @Query("q") String query, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<Group>> FindGroups(@Path("ns") String ns, @Query("q") String query, @Query("page") Integer page);

    @POST("api/v1/groups/in/{ns}")
    Call<Group> CreateGroup(@Path("ns") String ns, @Body CreateGroupRequest payload);
    @@ -36,31 +40,31 @@ public interface GroupsService {
    * {@link GroupMembership} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/membership")
    Call<Paged<GroupMembership>> QueryUserMembership(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupMembership>> QueryUserMembership(@Path("ns") String ns, @Path("accountId") String accountId, @Query("page") Integer page);

    /**
    * {@link GroupApplication} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/applications/outgoing")
    Call<Paged<GroupApplication>> QueryOutgoingApplications(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupApplication>> QueryOutgoingApplications(@Path("ns") String ns, @Path("accountId") String accountId, @Query("page") Integer page);

    /**
    * {@link GroupApplication} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/applications/incoming")
    Call<Paged<GroupApplication>> QueryIncomingApplications(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupApplication>> QueryIncomingApplications(@Path("ns") String ns, @Path("accountId") String accountId, @Query("page") Integer page);

    /**
    * {@link GroupInvitation} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/invitations/outgoing")
    Call<Paged<GroupInvitation>> QueryOutgoingInvitations(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupInvitation>> QueryOutgoingInvitations(@Path("ns") String ns, @Path("accountId") String accountId, @Query("page") Integer page);

    /**
    * {@link GroupInvitation} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/invitations/incoming")
    Call<Paged<GroupInvitation>> QueryIncomingInvitations(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupInvitation>> QueryIncomingInvitations(@Path("ns") String ns, @Path("accountId") String accountId, @Query("page") Integer page);

    @GET("api/v1/groups/{groupId}")
    Call<Group> QueryGroupInfo(@Path("groupId") String groupId);
    @@ -75,14 +79,15 @@ public interface GroupsService {
    Call<Void> TransferGroup(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/members")
    Call<Paged<GroupMember>> QueryGroupRoster(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupMember>> QueryGroupRoster(@Path("groupId") String groupId, @Query("page") Integer page);

    @GET("api/v1/groups/{groupId}/members/{accountId}")
    Call<GroupMember> QueryGroupMember(@Path("groupId") String groupId, @Path("accountId") String accountId);

    // 404, errors.com.epicgames.social.groups.not_found.group, Group has not been found: group (id=a168ccedec5b4c4f834f10677005ffdd) does not exists or is not of proper type (type=KAIROS)
    // Maybe for joining the group if the group is open (doesn't require approval)
    @POST("api/v1/groups/{groupId}/members/{accountId}")
    @Headers("Content-Type: application/json")
    Call<JsonElement> UNKNOWN(@Path("groupId") String groupId, @Path("accountId") String accountId);

    /**
    @@ -92,7 +97,7 @@ public interface GroupsService {
    Call<Void> RemoveUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/admins")
    Call<Paged<String>> QueryGroupAdmins(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<String>> QueryGroupAdmins(@Path("groupId") String groupId, @Query("page") Integer page);

    @PUT("api/v1/groups/{groupId}/admins/{accountId}")
    Call<Void> PromoteUser(@Path("groupId") String groupId, @Path("accountId") String accountId);
    @@ -107,43 +112,49 @@ public interface GroupsService {
    Call<Boolean> QueryGroupNameExist(@Path("ns") String ns, @Path("name") String name);

    @GET("api/v1/groups/{groupId}/invitations")
    Call<Paged<GroupInvitation>> QueryGroupInvites(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupInvitation>> QueryGroupInvites(@Path("groupId") String groupId, @Query("page") Integer page);

    @GET("api/v1/groups/{groupId}/invitations/{accountId}")
    Call<GroupInvitation> QueryGroupInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/invitations/{accountId}")
    @Headers("Content-Type: application/json")
    Call<GroupInvitation> InviteUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @DELETE("api/v1/groups/{groupId}/invitations/{accountId}")
    Call<Void> CancelInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/invitations/{accountId}/accept")
    @Headers("Content-Type: application/json")
    Call<GroupMember> AcceptInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/invitations/{accountId}/reject")
    @Headers("Content-Type: application/json")
    Call<GroupInvitation> DeclineInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/applications")
    Call<Paged<GroupApplication>> QueryGroupRequests(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupApplication>> QueryGroupRequests(@Path("groupId") String groupId, @Query("page") Integer page);

    @GET("api/v1/groups/{groupId}/applications/{accountId}")
    Call<GroupApplication> QueryGroupRequest(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/applications/{accountId}")
    @Headers("Content-Type: application/json")
    Call<GroupApplication> JoinGroup(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @DELETE("api/v1/groups/{groupId}/applications/{accountId}")
    Call<Void> CancelGroupRequest(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/applications/{accountId}/accept")
    @Headers("Content-Type: application/json")
    Call<GroupMember> AcceptUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/applications/{accountId}/reject")
    @Headers("Content-Type: application/json")
    Call<GroupApplication> DeclineUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/blacklist")
    Call<Paged<GroupBlacklistEntry>> QueryGroupBlacklist(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);
    Call<Paged<GroupBlacklistEntry>> QueryGroupBlacklist(@Path("groupId") String groupId, @Query("page") Integer page);

    @PUT("api/v1/groups/{groupId}/blacklist/{accountId}")
    Call<GroupBlacklistEntry> BlockUser(@Path("groupId") String groupId, @Path("accountId") String accountId);
  6. @Amrsatrio Amrsatrio revised this gist Jan 17, 2020. 8 changed files with 495 additions and 120 deletions.
    52 changes: 27 additions & 25 deletions AccountPublicService.java → AccountService.java
    Original file line number Diff line number Diff line change
    @@ -25,12 +25,14 @@
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface AccountPublicService {
    String BASE_URL = "https://account-public-service-prod.ol.epicgames.com";
    public interface AccountService {
    String BASE_URL_PROD = "https://account-public-service-prod.ol.epicgames.com/account/";
    String BASE_URL_PROD_ALT = "https://account-public-service-prod.ak.epicgames.com/account/";
    String BASE_URL_STAGE = "https://account-public-service-stage.ol.epicgames.com/account/";

    /**
    * grant_type: authorization_code; fields: code
    * grant_type: client_credentials -- used to retrieve client ID without sign in
    * grant_type: client_credentials
    * grant_type: device_auth; fields: account_id, device_id, secret
    * grant_type: exchange_code; fields: exchange_code
    * grant_type: external_auth; fields: external_auth_type, external_auth_token
    @@ -39,70 +41,70 @@ public interface AccountPublicService {
    * grant_type: refresh_token; fields: refresh_token
    */
    @FormUrlEncoded
    @POST("/account/api/oauth/token")
    @POST("api/oauth/token")
    Call<LoginResponse> grantToken(@Header("Authorization") String auth, @Field("grant_type") String grantType, @FieldMap Map<String, String> fields, @Field("includePerms") Boolean includePerms);

    @GET("/account/api/oauth/exchange")
    Call<ExchangeResponse> exchangeToken();
    @GET("api/oauth/exchange")
    Call<ExchangeResponse> generateExchangeCode();

    @GET("/account/api/oauth/verify")
    @GET("api/oauth/verify")
    Call<VerifyResponse> verifyToken(@Query("includePerms") Boolean includePerms);

    @DELETE("/account/api/oauth/sessions/kill/{accessToken}")
    @DELETE("api/oauth/sessions/kill/{accessToken}")
    Call<Void> killAuthSession(@Path("accessToken") String accessToken);

    /**
    * @param killType OTHERS, ALL_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT_SERVICE
    */
    @DELETE("/account/api/oauth/sessions/kill")
    @DELETE("api/oauth/sessions/kill")
    Call<Void> killAuthSessions(@Query("killType") String killType);

    @GET("/account/api/public/account")
    @GET("api/public/account")
    Call<GameProfile[]> queryUserInfo(@Query("accountId") List<String> ids);

    @GET("/account/api/public/account/{id}")
    @GET("api/public/account/{id}")
    Call<XGameProfile> queryUserInfo(@Path("id") String id);

    @GET("/account/api/accounts/{id}/metadata")
    @GET("api/accounts/{id}/metadata")
    Call<JsonObject> queryUserMetaData(@Path("id") String id);

    @GET("/account/api/public/account/{accountId}/deviceAuth")
    @GET("api/public/account/{accountId}/deviceAuth")
    Call<DeviceAuth[]> queryDeviceAuths(@Path("accountId") String accountId);

    @GET("/account/api/public/account/{accountId}/deviceAuth/{deviceId}")
    @GET("api/public/account/{accountId}/deviceAuth/{deviceId}")
    Call<DeviceAuth> queryDeviceAuths(@Path("accountId") String accountId, @Path("deviceId") String deviceId);

    @POST("/account/api/public/account/{accountId}/deviceAuth")
    @POST("api/public/account/{accountId}/deviceAuth")
    Call<DeviceAuth> createDeviceAuth(@Path("accountId") String accountId, @Header("X-Epic-Device-Info") String deviceInfo);

    @DELETE("/account/api/public/account/{accountId}/deviceAuth/{deviceId}")
    @DELETE("api/public/account/{accountId}/deviceAuth/{deviceId}")
    Call<Void> deleteDeviceAuth(@Path("accountId") String accountId, @Path("deviceId") String deviceId);

    @GET("/account/api/public/account/{id}/externalAuths")
    @GET("api/public/account/{id}/externalAuths")
    Call<ExternalAuth[]> queryExternalAccounts(@Path("id") String id);

    @GET("/account/api/public/account/{id}/externalAuths/{type}")
    @GET("api/public/account/{id}/externalAuths/{type}")
    Call<ExternalAuth> queryExternalAccountsByType(@Path("id") String id, @Path("type") String type);

    // TODO @POST("/account/api/public/account/{id}/externalAuths")
    // TODO @POST("api/public/account/{id}/externalAuths")
    // JsonObject: authType, externalAuthToken
    // Call<ExternalAuth[]> addExternalAccount(@Path("id") String id, @Body AddExternalAccountPayload payload);

    @DELETE("/account/api/public/account/{id}/externalAuths/{type}")
    @DELETE("api/public/account/{id}/externalAuths/{type}")
    Call<Void> removeExternalAccount(@Path("id") String id, @Path("type") String type);

    @GET("/account/api/public/account/displayName/{name}")
    @GET("api/public/account/displayName/{name}")
    Call<GameProfile> queryUserIdFromDisplayName(@Path("name") String name);

    @GET("/account/api/public/account/email/{email}")
    @GET("api/public/account/email/{email}")
    Call<GameProfile> queryUserIdFromEmail(@Path("email") String email);

    @POST("/account/api/public/account/lookup/externalId")
    @POST("api/public/account/lookup/externalId")
    Call<Map<String, ExternalAuth>> queryExternalIdMappingsById(@Body QueryExternalIdMappingsByIdPayload payload);

    @GET("/account/api/public/account/lookup/externalAuth/{externalAuthType}/displayName/{displayName}")
    @GET("api/public/account/lookup/externalAuth/{externalAuthType}/displayName/{displayName}")
    Call<GameProfile[]> queryExternalIdMappingsByDisplayName(@Path("externalAuthType") String externalAuthType, @Path("displayName") String displayName, @Query("caseInsensitive") Boolean caseInsensitive);

    @GET("/account/api/epicdomains/ssodomains")
    @GET("api/epicdomains/ssodomains")
    Call<String[]> querySSODomains();
    }
    46 changes: 46 additions & 0 deletions CatalogService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.tb24.fn.model.EpicGraphQLTypes;
    import com.tb24.fn.model.Paged;

    import java.util.List;
    import java.util.Map;

    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface CatalogService {
    String BASE_URL_PROD = "https://catalog-public-service-prod06.ol.epicgames.com/catalog/";
    String BASE_URL_PROD_ALT = "https://catalog-public-service-prod06.ak.epicgames.com/catalog/";
    String BASE_URL_STAGE = "https://catalogv2-public-service-stage.ol.epicgames.com/catalog/";

    // TODO research
    @GET("api/shared/categories")
    Call<JsonElement> queryCategories();

    @GET("api/shared/currencies")
    Call<Paged<EpicGraphQLTypes.Currency>> queryCurrencies(@Query("start") Integer start, @Query("count") Integer count);

    @GET("api/shared/namespace/{namespace}/items")
    Call<Paged<EpicGraphQLTypes.CatalogItem>> queryItems(@Path("namespace") String namespace, @Query("includeDLCDetails") Boolean includeDLCDetails, @Query("includeMainGameDetails") Boolean includeMainGameDetails, @Query("status") String status, @Query("sortBy") String sortBy, @Query("country") String country, @Query("locale") String locale, @Query("start") Integer start, @Query("count") Integer count);

    @GET("api/shared/namespace/{namespace}/offers")
    Call<Paged<EpicGraphQLTypes.CatalogOffer>> queryOffers(@Path("namespace") String namespace, @Query("status") String status, /* Maybe */ @Query("country") String country, @Query("locale") String locale, @Query("start") Integer start, @Query("count") Integer count, @Query("returnItemDetails") Boolean returnItemDetails);

    // TODO research
    @GET("api/shared/bulk/items")
    Call<Map<String, EpicGraphQLTypes.CatalogItem>> queryItemsBulk();

    // Used in Fortnite
    @GET("api/shared/bulk/offers")
    Call<Map<String, EpicGraphQLTypes.CatalogOffer>> queryOffersBulk(@Query("id") List<String> ids, @Query("returnItemDetails") Boolean returnItemDetails, @Query("country") String country, @Query("locale") String locale);

    @GET("api/shared/namespace/{namespace}/bulk/items")
    Call<Map<String, EpicGraphQLTypes.CatalogItem>> queryItemsBulkNamespace(@Path("namespace") String namespace, List<String> ids, @Query("includeDLCDetails") Boolean includeDLCDetails, @Query("includeMainGameDetails") Boolean includeMainGameDetails, @Query("country") String country, @Query("locale") String locale);

    @GET("api/shared/namespace/{namespace}/bulk/offers")
    Call<Map<String, EpicGraphQLTypes.CatalogOffer>> queryOffersBulkNamespace(@Path("namespace") String namespace);
    }
    93 changes: 93 additions & 0 deletions ChannelsService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,93 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.tb24.fn.model.EpicGraphQLTypes;
    import com.tb24.fn.model.UserSetting;

    import java.util.List;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.Field;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface ChannelsService {
    String BASE_URL_PROD = "https://channels-public-service-prod.ol.epicgames.com/";
    String BASE_URL_STAGE = "https://channels-public-service-stage.ol.epicgames.com/";

    @GET("api/v1/user/{accountId}?type=all")
    Call<EpicGraphQLTypes.ChannelSummary> QueryChannelList(@Path("accountId") String accountId);

    @POST("api/v1/channel")
    Call<JsonElement> CreateChannel(@Body EpicGraphQLTypes.CreateChannelRequest payload);

    @DELETE("api/v1/channel/{channelId}/members/{accountId}")
    Call<Void> LeaveChannel(@Path("channelId") String channelId, @Path("accountId") String accountId);

    @GET("api/v1/channel/{channelId}")
    Call<EpicGraphQLTypes.Channel> QueryChannelDetails(@Path("channelId") String channelId);

    // returns 204 by any means
    @POST("api/v1/channel/{channelId}")
    Call<JsonElement> UNKNOWN(@Path("channelId") String channelId);

    @GET("api/v1/channel/{channelId}/members")
    Call<JsonElement> AddToChannel(@Path("channelId") String channelId);

    @GET("api/v1/channel/{channelId}/messages")
    Call<EpicGraphQLTypes.MessagesResult> QueryChannelMessages(@Path("channelId") String channelId);

    @POST("api/v1/channel/{channelId}/messages")
    Call<EpicGraphQLTypes.MesssageCreateResult> SendMessageToChannel(@Path("channelId") String channelId, @Body EpicGraphQLTypes.CreateMessageRequest payload);

    @GET("api/v1/channel/{channelId}/messages/{messageId}")
    Call<EpicGraphQLTypes.MessageResult> QuerySingleChannelMessage(@Path("channelId") String channelId, @Path("messageId") String messageId);

    @DELETE("api/v1/channel/{channelId}/messages/{messageId}")
    Call<Void> DeleteMessageFromChannel(@Path("channelId") String channelId, @Path("messageId") String messageId);

    @GET("api/v1/dm/{accountId}/{peerUserId}/messages")
    Call<JsonElement> QueryDirectMessages(@Path("accountId") String accountId, @Path("peerUserId") String peerUserId);

    @POST("api/v1/dm/{accountId}/{peerUserId}/messages")
    Call<JsonElement> SendDirectMessage(@Path("accountId") String accountId, @Path("peerUserId") String peerUserId);

    @GET("api/v1/dm/{accountId}/{peerUserId}/messages/{messageId}")
    Call<JsonElement> QuerySingleDirectMessage(@Path("accountId") String accountId, @Path("peerUserId") String peerUserId, @Path("messageId") String messageId);

    @DELETE("api/v1/dm/{accountId}/{peerUserId}/messages/{messageId}")
    Call<Void> DeleteDirectMessage(@Path("accountId") String accountId, @Path("peerUserId") String peerUserId, @Path("messageId") String messageId);

    @GET("api/v1/user/{accountId}/setting/{settingKey}")
    Call<UserSetting> QueryUserSetting(@Path("accountId") String accountId, @Path("settingKey") String settingKey);

    /**
    * @param newSetting only {@link UserSetting#value} is required and read by the server.
    */
    @PUT("api/v1/user/{accountId}/setting/{settingKey}")
    Call<Void> UpdateUserSetting(@Path("accountId") String accountId, @Path("settingKey") String settingKey, @Body UserSetting newSetting);

    @GET("api/v1/user/{accountId}/setting/{settingKey}/available")
    Call<String[]> QueryAvailableUserSettingValues(@Path("accountId") String accountId, @Path("settingKey") String settingKey);

    @GET("api/v1/user/setting/{settingKey}")
    Call<UserSetting[]> QueryMultiUserSingleSetting(@Query("accountId") List<String> accountIds, @Path("settingKey") String settingKey);

    @POST("api/v1/user/setting/{settingKey}")
    Call<UserSetting[]> QueryMultiUserSingleSetting_Field(@Field("accountId") List<String> accountIds, @Path("settingKey") String settingKey);

    @GET("api/v1/user/setting")
    Call<UserSetting[]> QueryMultiUserMultiSetting(@Query("accountId") List<String> accountIds, @Query("settingKey") List<String> settingKeys);

    @POST("api/v1/user/setting")
    Call<UserSetting[]> QueryMultiUserMultiSetting_Field(@Field("accountId") List<String> accountIds, @Field("settingKey") List<String> settingKeys);

    // TODO Unknown method, cannot be tested
    // @POST("api/v1/user/{accountId}/notifyActive")
    // Call<JsonElement> SendNotifyActive(@Path("accountId") String accountId);
    }
    39 changes: 22 additions & 17 deletions EventsPublicService.java → EventsService.java
    Original file line number Diff line number Diff line change
    @@ -10,8 +10,13 @@
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface EventsPublicService {
    String BASE_URL = "https://events-public-service-live.ol.epicgames.com";
    public interface EventsService {
    /** default */
    String BASE_URL_LIVE = "https://events-public-service-live.ol.epicgames.com/";
    String BASE_URL_LIVE_ALT = "https://events-public-service-live.ak.epicgames.com/";
    String BASE_URL_LOAD_TEST = "https://events-public-service-loadtest.ol.epicgames.com/";
    String BASE_URL_PROD = "https://events-public-service-prod.ol.epicgames.com/";
    String BASE_URL_STAGE = "https://events-public-service-stage.ol.epicgames.com/";

    /**
    * @param gameId "Fortnite"
    @@ -20,7 +25,7 @@ public interface EventsPublicService {
    * @param platformName "Windows"
    * @param teamAccountIds "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/events/{GameId}/download/{AccountId}")
    @GET("api/v1/events/{GameId}/download/{AccountId}")
    Call<EventDownloadResponse> download(@Path("GameId") String gameId, @Path("AccountId") String accountId, @Query("region") String regionId, @Query("platform") String platformName, @Query("teamAccountIds") String teamAccountIds);

    /**
    @@ -31,7 +36,7 @@ public interface EventsPublicService {
    * @param regionId "ASIA"
    * @param bShowPastEvents ???
    */
    @GET("/api/v1/events/{GameId}/data/{AccountId}")
    @GET("api/v1/events/{GameId}/data/{AccountId}")
    Call<JsonElement> data(@Path("GameId") String gameId, @Path("AccountId") String accountId, @Query("region") String regionId, @Query("showPastEvents") Boolean bShowPastEvents);

    /**
    @@ -41,28 +46,28 @@ public interface EventsPublicService {
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param eventWindowId "OnlineOpen_Week2_ASIA_Event2"
    */
    @GET("/api/v1/events/{GameId}/{EventId}/{EventWindowId}/history")
    @GET("api/v1/events/{GameId}/{EventId}/{EventWindowId}/history")
    Call<JsonElement> history(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("EventWindowId") String eventWindowId);

    /**
    * @param gameId "Fortnite"
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param eventWindowId "OnlineOpen_Week2_ASIA_Event2"
    * @param accountId "00112233445566778899aabbccddeeff"
    * @param page 0
    * @param rank 0
    * @param teamAccountIds ""
    * @param appId "Fortnite"
    * @param gameId "Fortnite"
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param eventWindowId "OnlineOpen_Week2_ASIA_Event2"
    * @param accountId "00112233445566778899aabbccddeeff"
    * @param page 0
    * @param rank 0
    * @param teamAccountIds ""
    * @param appId "Fortnite"
    * @param bShowLiveSessions "false"
    */
    @GET("/api/v1/leaderboards/{GameId}/{EventId}/{EventWindowId}/{AccountId}")
    @GET("api/v1/leaderboards/{GameId}/{EventId}/{EventWindowId}/{AccountId}")
    Call<LeaderboardsResponse> leaderboards(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("EventWindowId") String eventWindowId, @Path("AccountId") String accountId, @Query("page") Integer page, @Query("rank") Integer rank, @Query("teamAccountIds") String teamAccountIds, @Query("appId") String appId, @Query("showLiveSessions") Boolean bShowLiveSessions);

    /**
    * @param gameId "Fortnite"
    * @param accountId "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/players/{GameId}/{AccountId}")
    @GET("api/v1/players/{GameId}/{AccountId}")
    Call<AccountCompetitiveData> eventDataForAccount(@Path("GameId") String gameId, @Path("AccountId") String accountId);

    /**
    @@ -72,7 +77,7 @@ public interface EventsPublicService {
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param accountId "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/events/{GameId}/{EventId}/history/{AccountId}")
    @GET("api/v1/events/{GameId}/{EventId}/history/{AccountId}")
    Call<JsonElement[]> eventHistoryForAccount(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("AccountId") String accountId);

    /**
    @@ -83,6 +88,6 @@ public interface EventsPublicService {
    * @param eventWindowId "OnlineOpen_Week2_ASIA_Event2"
    * @param accountId "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/events/{GameId}/{EventId}/{EventWindowId}/history/{AccountId}")
    @GET("api/v1/events/{GameId}/{EventId}/{EventWindowId}/history/{AccountId}")
    Call<JsonElement[]> eventWindowHistoryForAccount(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("EventWindowId") String eventWindowId, @Path("AccountId") String accountId);
    }
    85 changes: 49 additions & 36 deletions FortnitePublicService.java → FortniteService.java
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,19 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.tb24.fn.model.AccountPrivacyResponse;
    import com.tb24.fn.model.CalendarTimelineResponse;
    import com.tb24.fn.model.CloudStorageFile;
    import com.tb24.fn.model.CloudStorageUsageInfo;
    import com.tb24.fn.model.FortCatalogResponse;
    import com.tb24.fn.model.FortMcpResponse;
    import com.tb24.fn.model.LinkEntry;
    import com.tb24.fn.model.LinksQueryResponse;
    import com.tb24.fn.model.QueryMultipleUserStats;
    import com.tb24.fn.model.Receipt;
    import com.tb24.fn.model.StatsV2Response;
    import com.tb24.fn.model.WorldInfoResponse;

    import okhttp3.RequestBody;
    import okhttp3.ResponseBody;
    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    @@ -23,84 +24,96 @@
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface FortnitePublicService {
    String BASE_URL = "https://fortnite-public-service-prod11.ol.epicgames.com";
    public interface FortniteService {
    String BASE_URL = "https://fortnite-public-service-prod11.ol.epicgames.com/fortnite/";

    @POST("/fortnite/api/game/v2/profile/{id}/client/{command}")
    @POST("api/game/v2/profile/{id}/client/{command}")
    Call<FortMcpResponse> clientCommand(@Path("command") String command, @Path("id") String accountId, @Query("profileId") String profileId, @Query("rvn") Integer currentProfileRevision, @Header("X-EpicGames-ProfileRevisions") String profileRevisionsMeta, @Body Object payload);

    @GET("/fortnite/api/game/v2/world/info")
    Call<WorldInfoResponse> pveWorldInfo();
    @GET("api/game/v2/world/info")
    Call<WorldInfoResponse> queryTheaterList(@Header("X-EpicGames-Language") String language);

    @GET("/fortnite/api/game/v2/privacy/account/{id}")
    @GET("api/game/v2/privacy/account/{id}")
    Call<AccountPrivacyResponse> getAccountPrivacy(@Path("id") String id);

    @POST("/fortnite/api/game/v2/privacy/account/{id}")
    @POST("api/game/v2/privacy/account/{id}")
    Call<AccountPrivacyResponse> setAccountPrivacy(@Path("id") String id, @Body AccountPrivacyResponse payload);

    @GET("/fortnite/api/storefront/v2/catalog")
    Call<FortCatalogResponse> storefrontCatalog();
    @GET("api/storefront/v2/catalog")
    Call<FortCatalogResponse> storefrontCatalog(@Header("X-EpicGames-Language") String language);

    @GET("/fortnite/api/calendar/v1/timeline")
    @GET("api/calendar/v1/timeline")
    Call<CalendarTimelineResponse> calendarTimeline();

    @GET("/fortnite/api/statsv2/account/{id}")
    Call<StatsV2Response> querySingleUserStats(@Path("id") String id, @Query("startTime") Long startTime, @Query("endTime") Long endTime);
    @GET("api/cloudstorage/system")
    Call<CloudStorageFile[]> enumerateTitleFiles();

    @POST("/fortnite/api/statsv2/query")
    Call<StatsV2Response[]> queryMultipleUserStats(@Body QueryMultipleUserStats payload);
    @GET("api/cloudstorage/system/{filename}")
    Call<ResponseBody> readTitleFile(@Path("filename") String filename);

    @GET("/fortnite/api/cloudstorage/user/{id}")
    Call<JsonObject[]> enumerateUserFiles(@Path("id") String id);
    @GET("api/cloudstorage/user/{id}")
    Call<CloudStorageFile[]> enumerateUserFiles(@Path("id") String id);

    @POST("/fortnite/api/game/v2/events/v2/processPendingRewards/{id}")
    @GET("api/cloudstorage/user/{id}/{filename}")
    Call<ResponseBody> readUserFile(@Path("id") String id, @Path("filename") String filename);

    @PUT("api/cloudstorage/user/{id}/{filename}")
    Call<Void> writeUserFile(@Path("id") String id, @Path("filename") String filename, @Body RequestBody newFile);

    @DELETE("api/cloudstorage/user/{id}/{filename}")
    Call<Void> deleteUserFile(@Path("id") String id, @Path("filename") String filename);

    @GET("api/cloudstorage/storage/{id}/info")
    Call<CloudStorageUsageInfo> requestUsageInfo(@Path("id") String accountId);

    @POST("api/game/v2/events/v2/processPendingRewards/{id}")
    Call<JsonElement[]> eventsProcessPendingRewards(@Path("id") String id);

    @GET("/fortnite/api/game/v2/tryPlayOnPlatform/account/{id}")
    Call<Boolean> tryPlayOnPlatform(@Path("id") String id, @Query("platform") String platform);
    /**
    * @param platform PC, MOBILE, PS4, XBOX_ONE, or SWITCH
    */
    @POST("api/game/v2/tryPlayOnPlatform/account/{id}")
    Call<Boolean> checkPlatformPlayAllowed(@Path("id") String id, @Query("platform") String platform);

    @GET("/fortnite/api/game/v2/enabled_features")
    @GET("api/game/v2/enabled_features")
    Call<JsonElement[]> enabledFeatures();

    @POST("/fortnite/api/game/v2/grant_access/{id}")
    @POST("api/game/v2/grant_access/{id}")
    Call<Void> grantAccess(@Path("id") String id);

    @GET("/fortnite/api/storefront/v2/keychain")
    @GET("api/storefront/v2/keychain")
    Call<String[]> storefrontKeychain(@Query("numKeysDownloaded") Integer numKeysDownloaded);

    @GET("/fortnite/api/receipts/v1/account/{id}/receipts")
    @GET("api/receipts/v1/account/{id}/receipts")
    Call<Receipt[]> receipts(@Path("id") String id);

    /**
    * @param olderThan in ISO 8601 date format
    */
    @GET("/fortnite/api/game/v2/creative/favorites/{accountId}")
    @GET("api/game/v2/creative/favorites/{accountId}")
    Call<LinksQueryResponse> queryCreativeFavorites(@Path("accountId") String accountId, @Query("limit") Integer limit, @Query("olderThan") String olderThan);

    @PUT("/fortnite/api/game/v2/creative/favorites/{accountId}/{mnemonic}")
    @PUT("api/game/v2/creative/favorites/{accountId}/{mnemonic}")
    Call<LinkEntry> addCodeToCreativeFavorites(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    /**
    * Requires permission fortnite:profile:MissingParameterValue:commands DELETE
    */
    @DELETE("/fortnite/api/game/v2/creative/favorites/{accountId}/{mnemonic}")
    @DELETE("api/game/v2/creative/favorites/{accountId}/{mnemonic}")
    Call<Void> removeCodeFromCreativeFavorites(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    /**
    * @param olderThan in ISO 8601 date format
    */
    @GET("/fortnite/api/game/v2/creative/history/{accountId}")
    @GET("api/game/v2/creative/history/{accountId}")
    Call<LinksQueryResponse> queryCreativeHistory(@Path("accountId") String accountId, @Query("limit") Integer limit, @Query("olderThan") String olderThan);

    /**
    * Requires permission fortnite:fortnite_role:dedicated_server ALL
    */
    @PUT("/fortnite/api/game/v2/creative/history/{accountId}/{mnemonic}")
    @PUT("api/game/v2/creative/history/{accountId}/{mnemonic}")
    Call<LinkEntry> addCodeToCreativeHistory(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    @DELETE("/fortnite/api/game/v2/creative/history/{accountId}/{mnemonic}")
    @DELETE("api/game/v2/creative/history/{accountId}/{mnemonic}")
    Call<Void> removeCodeFromCreativeHistory(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    @GET("/fortnite/api/storefront/v2/gift/check_eligibility/recipient/{recipientAccountId}/offer/{offerId}")
    @GET("api/storefront/v2/gift/check_eligibility/recipient/{recipientAccountId}/offer/{offerId}")
    Call<Void> checkGiftEligibility(@Path("recipientAccountId") String recipientAccountId, @Path("offerId") String offerId);
    }
    42 changes: 0 additions & 42 deletions FriendsPublicService.java
    Original file line number Diff line number Diff line change
    @@ -1,42 +0,0 @@
    package com.tb24.fn.network;

    import com.tb24.fn.model.BlockedUsers;
    import com.tb24.fn.model.Friend;
    import com.tb24.fn.model.FriendsSettings;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface FriendsPublicService {
    String BASE_URL = "https://friends-public-service-prod.ol.epicgames.com";

    @GET("/friends/api/public/friends/{id}")
    Call<Friend[]> friends(@Path("id") String id, @Query("includePending") Boolean includePending);

    @POST("/friends/api/public/friends/{id}/{friend}")
    Call<Void> inviteOrAccept(@Path("id") String id, @Path("friend") String friend);

    @DELETE("/friends/api/public/friends/{id}/{friend}")
    Call<Void> removeOrReject(@Path("id") String id, @Path("friend") String friend);

    @GET("/friends/api/public/blocklist/{id}")
    Call<BlockedUsers> blockList(@Path("id") String id);

    // @GET("/friends/api/public/blocklist/{id}/{block}")
    // Call<Friend> blockList(@Path("id") String id, @Path("block") String block);

    @GET("/friends/api/public/list/{namespace}/{id}/recentPlayers")
    Call<Friend[]> recentPlayers(@Path("namespace") String namespace, @Path("id") String id);

    @GET("/friends/api/v1/{id}/settings")
    Call<FriendsSettings> settings(@Path("id") String id);

    @PUT("/friends/api/v1/{id}/settings")
    Call<FriendsSettings> setSettings(@Path("id") String id, @Body FriendsSettings newSettings);
    }
    99 changes: 99 additions & 0 deletions FriendsService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonObject;
    import com.tb24.fn.model.BlockedUsers;
    import com.tb24.fn.model.Friend;
    import com.tb24.fn.model.FriendV2;
    import com.tb24.fn.model.FriendsSettings;
    import com.tb24.fn.model.FriendsV2Summary;

    import okhttp3.RequestBody;
    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface FriendsService {
    String BASE_URL_PROD = "https://friends-public-service-prod.ol.epicgames.com/friends/";
    String BASE_URL_PROD_ALT = "https://friends-public-service-prod.ak.epicgames.com/friends/";
    String BASE_URL_STAGE = "https://friends-public-service-stage.ol.epicgames.com/friends/";

    @GET("api/v1/{id}/summary")
    Call<FriendsV2Summary> queryFriendsSummary(@Path("id") String id, @Query("displayNames") Boolean displayNames);

    @GET("api/v1/{id}/friends")
    Call<FriendV2[]> queryFriends(@Path("id") String id, @Query("displayNames") Boolean displayNames);

    @GET("api/v1/{id}/friends/{friend}")
    Call<FriendV2> queryFriend(@Path("id") String id, @Path("friend") String friend, @Query("displayNames") Boolean displayNames);

    @POST("api/v1/{id}/friends/{friend}")
    Call<Void> sendInviteOrAcceptInvite(@Path("id") String id, @Path("friend") String friend);

    @DELETE("api/v1/{id}/friends/{friend}")
    Call<Void> deleteFriendOrRejectInvite(@Path("id") String id, @Path("friend") String friend);

    @PUT("api/v1/{id}/friends/{friend}/alias")
    Call<Void> setFriendAlias(@Path("id") String id, @Path("friend") String friend, @Body RequestBody newAlias);

    @DELETE("api/v1/{id}/friends/{friend}/alias")
    Call<Void> deleteFriendAlias(@Path("id") String id, @Path("friend") String friend);

    @PUT("api/v1/{id}/friends/{friend}/note")
    Call<Void> setFriendNote(@Path("id") String id, @Path("friend") String friend, @Body RequestBody newNote);

    @DELETE("api/v1/{id}/friends/{friend}/note")
    Call<Void> deleteFriendNote(@Path("id") String id, @Path("friend") String friend);

    @GET("api/v1/{id}/incoming")
    Call<FriendV2[]> queryIncomingFriendRequests(@Path("id") String id, @Query("displayNames") Boolean displayNames);

    @GET("api/v1/{id}/outgoing")
    Call<FriendV2[]> queryOutgoingFriendRequests(@Path("id") String id, @Query("displayNames") Boolean displayNames);

    @GET("api/v1/{id}/blocklist")
    Call<FriendV2[]> queryBlockedPlayers(@Path("id") String id, @Query("displayNames") Boolean displayNames);

    @POST("api/v1/{id}/blocklist/{block}")
    Call<Void> sendBlock(@Path("id") String id, @Path("block") String block);

    @DELETE("api/v1/{id}/blocklist/{block}")
    Call<Void> sendUnblock(@Path("id") String id, @Path("block") String block);

    /**
    * @param namespace ex: "fortnite"
    */
    @GET("api/v1/{id}/recent/{namespace}")
    Call<Friend[]> queryRecentPlayers(@Path("id") String id, @Path("namespace") String namespace);

    // TODO unknown parameters, 403 for user access token
    @POST("api/v1/recent/{namespace}")
    Call<Void> addBulkRecentPlayers(@Path("namespace") String namespace);

    @GET("api/v1/{id}/settings")
    Call<FriendsSettings> queryFriendSettings(@Path("id") String id);

    @PUT("api/v1/{id}/settings")
    Call<FriendsSettings> setFriendSettings(@Path("id") String id, @Body FriendsSettings newSettings);

    /**
    * @param source ex: "steam"
    */
    @GET("api/v1/{id}/settings/externalSources/{source}")
    Call<JsonObject> queryFriendExternalSourceSettings(@Path("id") String id, @Path("source") String source);

    @PUT("api/v1/{id}/settings/externalSources/{source}")
    Call<JsonObject> setFriendExternalSourceSettings(@Path("id") String id, @Path("source") String source, @Body JsonObject newSettings);

    @Deprecated
    @GET("api/public/friends/{id}")
    Call<Friend[]> LEGACY_queryFriends(@Path("id") String id, @Query("includePending") Boolean includePending);

    @Deprecated
    @GET("api/public/blocklist/{id}")
    Call<BlockedUsers> LEGACY_queryBlockedPlayers(@Path("id") String id);
    }
    159 changes: 159 additions & 0 deletions GroupsService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,159 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.tb24.fn.model.CreateGroupRequest;
    import com.tb24.fn.model.Group;
    import com.tb24.fn.model.GroupApplication;
    import com.tb24.fn.model.GroupBlacklistEntry;
    import com.tb24.fn.model.GroupInvitation;
    import com.tb24.fn.model.GroupMember;
    import com.tb24.fn.model.GroupMembership;
    import com.tb24.fn.model.GroupSimpleInfo;
    import com.tb24.fn.model.GroupUpdatePayload;
    import com.tb24.fn.model.Paged;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface GroupsService {
    String BASE_URL_PROD = "https://groups-service-prod06.ol.epicgames.com/groups/";
    String BASE_URL_PROD_ALT = "https://groups-service-prod.ak.epicgames.com/groups/";
    String BASE_URL_PROD_STAGE = "https://groups-service-stage.ol.epicgames.com/groups/";

    @GET("api/v1/groups/in/{ns}")
    Call<Paged<Group>> FindGroups(@Path("ns") String ns, @Query("q") String query, @Query("start") Integer start, @Query("count") Integer count);

    @POST("api/v1/groups/in/{ns}")
    Call<Group> CreateGroup(@Path("ns") String ns, @Body CreateGroupRequest payload);

    /**
    * {@link GroupMembership} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/membership")
    Call<Paged<GroupMembership>> QueryUserMembership(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);

    /**
    * {@link GroupApplication} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/applications/outgoing")
    Call<Paged<GroupApplication>> QueryOutgoingApplications(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);

    /**
    * {@link GroupApplication} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/applications/incoming")
    Call<Paged<GroupApplication>> QueryIncomingApplications(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);

    /**
    * {@link GroupInvitation} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/invitations/outgoing")
    Call<Paged<GroupInvitation>> QueryOutgoingInvitations(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);

    /**
    * {@link GroupInvitation} contains {@link GroupSimpleInfo}.
    */
    @GET("api/v1/user/in/{ns}/{accountId}/invitations/incoming")
    Call<Paged<GroupInvitation>> QueryIncomingInvitations(@Path("ns") String ns, @Path("accountId") String accountId, @Query("start") Integer start, @Query("count") Integer count);

    @GET("api/v1/groups/{groupId}")
    Call<Group> QueryGroupInfo(@Path("groupId") String groupId);

    @POST("api/v1/groups/{groupId}")
    Call<Group> UpdateGroupInfo(@Path("groupId") String groupId, @Body GroupUpdatePayload payload);

    @DELETE("api/v1/groups/{groupId}")
    Call<Void> DeleteGroup(@Path("groupId") String groupId);

    @PUT("api/v1/groups/{groupId}/owner/{accountId}")
    Call<Void> TransferGroup(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/members")
    Call<Paged<GroupMember>> QueryGroupRoster(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);

    @GET("api/v1/groups/{groupId}/members/{accountId}")
    Call<GroupMember> QueryGroupMember(@Path("groupId") String groupId, @Path("accountId") String accountId);

    // 404, errors.com.epicgames.social.groups.not_found.group, Group has not been found: group (id=a168ccedec5b4c4f834f10677005ffdd) does not exists or is not of proper type (type=KAIROS)
    // Maybe for joining the group if the group is open (doesn't require approval)
    @POST("api/v1/groups/{groupId}/members/{accountId}")
    Call<JsonElement> UNKNOWN(@Path("groupId") String groupId, @Path("accountId") String accountId);

    /**
    * Can also be used to leave the group.
    */
    @DELETE("api/v1/groups/{groupId}/members/{accountId}")
    Call<Void> RemoveUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/admins")
    Call<Paged<String>> QueryGroupAdmins(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);

    @PUT("api/v1/groups/{groupId}/admins/{accountId}")
    Call<Void> PromoteUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @DELETE("api/v1/groups/{groupId}/admins/{accountId}")
    Call<Void> DemoteUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/in/{ns}/{name}")
    Call<Group> QueryGroupByName(@Path("ns") String ns, @Path("name") String name);

    @GET("api/v1/groups/in/{ns}/{name}/exist")
    Call<Boolean> QueryGroupNameExist(@Path("ns") String ns, @Path("name") String name);

    @GET("api/v1/groups/{groupId}/invitations")
    Call<Paged<GroupInvitation>> QueryGroupInvites(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);

    @GET("api/v1/groups/{groupId}/invitations/{accountId}")
    Call<GroupInvitation> QueryGroupInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/invitations/{accountId}")
    Call<GroupInvitation> InviteUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @DELETE("api/v1/groups/{groupId}/invitations/{accountId}")
    Call<Void> CancelInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/invitations/{accountId}/accept")
    Call<GroupMember> AcceptInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/invitations/{accountId}/reject")
    Call<GroupInvitation> DeclineInvite(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/applications")
    Call<Paged<GroupApplication>> QueryGroupRequests(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);

    @GET("api/v1/groups/{groupId}/applications/{accountId}")
    Call<GroupApplication> QueryGroupRequest(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/applications/{accountId}")
    Call<GroupApplication> JoinGroup(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @DELETE("api/v1/groups/{groupId}/applications/{accountId}")
    Call<Void> CancelGroupRequest(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/applications/{accountId}/accept")
    Call<GroupMember> AcceptUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @POST("api/v1/groups/{groupId}/applications/{accountId}/reject")
    Call<GroupApplication> DeclineUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/groups/{groupId}/blacklist")
    Call<Paged<GroupBlacklistEntry>> QueryGroupBlacklist(@Path("groupId") String groupId, @Query("start") Integer start, @Query("count") Integer count);

    @PUT("api/v1/groups/{groupId}/blacklist/{accountId}")
    Call<GroupBlacklistEntry> BlockUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @DELETE("api/v1/groups/{groupId}/blacklist/{accountId}")
    Call<Void> UnblockUser(@Path("groupId") String groupId, @Path("accountId") String accountId);

    @GET("api/v1/config/{ns}/limits/headcount")
    Call<Integer> QueryConfigHeadcount(@Path("ns") String ns);

    @GET("api/v1/config/{ns}/limits/membership")
    Call<Integer> QueryConfigMembership(@Path("ns") String ns);
    }
  7. @Amrsatrio Amrsatrio revised this gist Oct 4, 2019. 3 changed files with 48 additions and 4 deletions.
    3 changes: 1 addition & 2 deletions AccountPublicService.java
    Original file line number Diff line number Diff line change
    @@ -54,9 +54,8 @@ public interface AccountPublicService {
    /**
    * @param killType OTHERS, ALL_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT_SERVICE
    */
    @FormUrlEncoded
    @DELETE("/account/api/oauth/sessions/kill")
    Call<Void> killAuthSessions(@Field("killType") String killType);
    Call<Void> killAuthSessions(@Query("killType") String killType);

    @GET("/account/api/public/account")
    Call<GameProfile[]> queryUserInfo(@Query("accountId") List<String> ids);
    40 changes: 40 additions & 0 deletions FortnitePublicService.java
    Original file line number Diff line number Diff line change
    @@ -6,16 +6,20 @@
    import com.tb24.fn.model.CalendarTimelineResponse;
    import com.tb24.fn.model.FortCatalogResponse;
    import com.tb24.fn.model.FortMcpResponse;
    import com.tb24.fn.model.LinkEntry;
    import com.tb24.fn.model.LinksQueryResponse;
    import com.tb24.fn.model.QueryMultipleUserStats;
    import com.tb24.fn.model.Receipt;
    import com.tb24.fn.model.StatsV2Response;
    import com.tb24.fn.model.WorldInfoResponse;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.Header;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    @@ -58,9 +62,45 @@ public interface FortnitePublicService {
    @GET("/fortnite/api/game/v2/enabled_features")
    Call<JsonElement[]> enabledFeatures();

    @POST("/fortnite/api/game/v2/grant_access/{id}")
    Call<Void> grantAccess(@Path("id") String id);

    @GET("/fortnite/api/storefront/v2/keychain")
    Call<String[]> storefrontKeychain(@Query("numKeysDownloaded") Integer numKeysDownloaded);

    @GET("/fortnite/api/receipts/v1/account/{id}/receipts")
    Call<Receipt[]> receipts(@Path("id") String id);

    /**
    * @param olderThan in ISO 8601 date format
    */
    @GET("/fortnite/api/game/v2/creative/favorites/{accountId}")
    Call<LinksQueryResponse> queryCreativeFavorites(@Path("accountId") String accountId, @Query("limit") Integer limit, @Query("olderThan") String olderThan);

    @PUT("/fortnite/api/game/v2/creative/favorites/{accountId}/{mnemonic}")
    Call<LinkEntry> addCodeToCreativeFavorites(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    /**
    * Requires permission fortnite:profile:MissingParameterValue:commands DELETE
    */
    @DELETE("/fortnite/api/game/v2/creative/favorites/{accountId}/{mnemonic}")
    Call<Void> removeCodeFromCreativeFavorites(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    /**
    * @param olderThan in ISO 8601 date format
    */
    @GET("/fortnite/api/game/v2/creative/history/{accountId}")
    Call<LinksQueryResponse> queryCreativeHistory(@Path("accountId") String accountId, @Query("limit") Integer limit, @Query("olderThan") String olderThan);

    /**
    * Requires permission fortnite:fortnite_role:dedicated_server ALL
    */
    @PUT("/fortnite/api/game/v2/creative/history/{accountId}/{mnemonic}")
    Call<LinkEntry> addCodeToCreativeHistory(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    @DELETE("/fortnite/api/game/v2/creative/history/{accountId}/{mnemonic}")
    Call<Void> removeCodeFromCreativeHistory(@Path("accountId") String accountId, @Path("mnemonic") String mnemonic);

    @GET("/fortnite/api/storefront/v2/gift/check_eligibility/recipient/{recipientAccountId}/offer/{offerId}")
    Call<Void> checkGiftEligibility(@Path("recipientAccountId") String recipientAccountId, @Path("offerId") String offerId);
    }
    9 changes: 7 additions & 2 deletions FriendsPublicService.java
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,15 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonObject;
    import com.tb24.fn.model.BlockedUsers;
    import com.tb24.fn.model.Friend;
    import com.tb24.fn.model.FriendsSettings;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.PUT;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    @@ -33,5 +35,8 @@ public interface FriendsPublicService {
    Call<Friend[]> recentPlayers(@Path("namespace") String namespace, @Path("id") String id);

    @GET("/friends/api/v1/{id}/settings")
    Call<JsonObject> settings(@Path("id") String id);
    Call<FriendsSettings> settings(@Path("id") String id);

    @PUT("/friends/api/v1/{id}/settings")
    Call<FriendsSettings> setSettings(@Path("id") String id, @Body FriendsSettings newSettings);
    }
  8. @Amrsatrio Amrsatrio revised this gist Jul 18, 2019. 3 changed files with 6 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions AccountPublicService.java
    Original file line number Diff line number Diff line change
    @@ -26,6 +26,8 @@
    import retrofit2.http.Query;

    public interface AccountPublicService {
    String BASE_URL = "https://account-public-service-prod.ol.epicgames.com";

    /**
    * grant_type: authorization_code; fields: code
    * grant_type: client_credentials -- used to retrieve client ID without sign in
    2 changes: 2 additions & 0 deletions FortnitePublicService.java
    Original file line number Diff line number Diff line change
    @@ -20,6 +20,8 @@
    import retrofit2.http.Query;

    public interface FortnitePublicService {
    String BASE_URL = "https://fortnite-public-service-prod11.ol.epicgames.com";

    @POST("/fortnite/api/game/v2/profile/{id}/client/{command}")
    Call<FortMcpResponse> clientCommand(@Path("command") String command, @Path("id") String accountId, @Query("profileId") String profileId, @Query("rvn") Integer currentProfileRevision, @Header("X-EpicGames-ProfileRevisions") String profileRevisionsMeta, @Body Object payload);

    2 changes: 2 additions & 0 deletions FriendsPublicService.java
    Original file line number Diff line number Diff line change
    @@ -12,6 +12,8 @@
    import retrofit2.http.Query;

    public interface FriendsPublicService {
    String BASE_URL = "https://friends-public-service-prod.ol.epicgames.com";

    @GET("/friends/api/public/friends/{id}")
    Call<Friend[]> friends(@Path("id") String id, @Query("includePending") Boolean includePending);

  9. @Amrsatrio Amrsatrio revised this gist Jul 17, 2019. 1 changed file with 88 additions and 0 deletions.
    88 changes: 88 additions & 0 deletions EventsPublicService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.tb24.fn.model.AccountCompetitiveData;
    import com.tb24.fn.model.EventDownloadResponse;
    import com.tb24.fn.model.LeaderboardsResponse;

    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface EventsPublicService {
    String BASE_URL = "https://events-public-service-live.ol.epicgames.com";

    /**
    * @param gameId "Fortnite"
    * @param accountId "00112233445566778899aabbccddeeff"
    * @param regionId "ASIA"
    * @param platformName "Windows"
    * @param teamAccountIds "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/events/{GameId}/download/{AccountId}")
    Call<EventDownloadResponse> download(@Path("GameId") String gameId, @Path("AccountId") String accountId, @Query("region") String regionId, @Query("platform") String platformName, @Query("teamAccountIds") String teamAccountIds);

    /**
    * TODO haven't tried
    *
    * @param gameId "Fortnite"
    * @param accountId "00112233445566778899aabbccddeeff"
    * @param regionId "ASIA"
    * @param bShowPastEvents ???
    */
    @GET("/api/v1/events/{GameId}/data/{AccountId}")
    Call<JsonElement> data(@Path("GameId") String gameId, @Path("AccountId") String accountId, @Query("region") String regionId, @Query("showPastEvents") Boolean bShowPastEvents);

    /**
    * TODO haven't tried
    *
    * @param gameId "Fortnite"
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param eventWindowId "OnlineOpen_Week2_ASIA_Event2"
    */
    @GET("/api/v1/events/{GameId}/{EventId}/{EventWindowId}/history")
    Call<JsonElement> history(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("EventWindowId") String eventWindowId);

    /**
    * @param gameId "Fortnite"
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param eventWindowId "OnlineOpen_Week2_ASIA_Event2"
    * @param accountId "00112233445566778899aabbccddeeff"
    * @param page 0
    * @param rank 0
    * @param teamAccountIds ""
    * @param appId "Fortnite"
    * @param bShowLiveSessions "false"
    */
    @GET("/api/v1/leaderboards/{GameId}/{EventId}/{EventWindowId}/{AccountId}")
    Call<LeaderboardsResponse> leaderboards(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("EventWindowId") String eventWindowId, @Path("AccountId") String accountId, @Query("page") Integer page, @Query("rank") Integer rank, @Query("teamAccountIds") String teamAccountIds, @Query("appId") String appId, @Query("showLiveSessions") Boolean bShowLiveSessions);

    /**
    * @param gameId "Fortnite"
    * @param accountId "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/players/{GameId}/{AccountId}")
    Call<AccountCompetitiveData> eventDataForAccount(@Path("GameId") String gameId, @Path("AccountId") String accountId);

    /**
    * TODO return object
    *
    * @param gameId "Fortnite"
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param accountId "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/events/{GameId}/{EventId}/history/{AccountId}")
    Call<JsonElement[]> eventHistoryForAccount(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("AccountId") String accountId);

    /**
    * TODO haven't tried
    *
    * @param gameId "Fortnite"
    * @param eventId "epicgames_OnlineOpen_Week2_ASIA"
    * @param eventWindowId "OnlineOpen_Week2_ASIA_Event2"
    * @param accountId "00112233445566778899aabbccddeeff"
    */
    @GET("/api/v1/events/{GameId}/{EventId}/{EventWindowId}/history/{AccountId}")
    Call<JsonElement[]> eventWindowHistoryForAccount(@Path("GameId") String gameId, @Path("EventId") String eventId, @Path("EventWindowId") String eventWindowId, @Path("AccountId") String accountId);
    }
  10. @Amrsatrio Amrsatrio revised this gist Jul 10, 2019. 1 changed file with 35 additions and 0 deletions.
    35 changes: 35 additions & 0 deletions FriendsPublicService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,35 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonObject;
    import com.tb24.fn.model.BlockedUsers;
    import com.tb24.fn.model.Friend;

    import retrofit2.Call;
    import retrofit2.http.DELETE;
    import retrofit2.http.GET;
    import retrofit2.http.POST;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface FriendsPublicService {
    @GET("/friends/api/public/friends/{id}")
    Call<Friend[]> friends(@Path("id") String id, @Query("includePending") Boolean includePending);

    @POST("/friends/api/public/friends/{id}/{friend}")
    Call<Void> inviteOrAccept(@Path("id") String id, @Path("friend") String friend);

    @DELETE("/friends/api/public/friends/{id}/{friend}")
    Call<Void> removeOrReject(@Path("id") String id, @Path("friend") String friend);

    @GET("/friends/api/public/blocklist/{id}")
    Call<BlockedUsers> blockList(@Path("id") String id);

    // @GET("/friends/api/public/blocklist/{id}/{block}")
    // Call<Friend> blockList(@Path("id") String id, @Path("block") String block);

    @GET("/friends/api/public/list/{namespace}/{id}/recentPlayers")
    Call<Friend[]> recentPlayers(@Path("namespace") String namespace, @Path("id") String id);

    @GET("/friends/api/v1/{id}/settings")
    Call<JsonObject> settings(@Path("id") String id);
    }
  11. @Amrsatrio Amrsatrio revised this gist Jul 10, 2019. 1 changed file with 64 additions and 0 deletions.
    64 changes: 64 additions & 0 deletions FortnitePublicService.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    import com.tb24.fn.model.AccountPrivacyResponse;
    import com.tb24.fn.model.CalendarTimelineResponse;
    import com.tb24.fn.model.FortCatalogResponse;
    import com.tb24.fn.model.FortMcpResponse;
    import com.tb24.fn.model.QueryMultipleUserStats;
    import com.tb24.fn.model.Receipt;
    import com.tb24.fn.model.StatsV2Response;
    import com.tb24.fn.model.WorldInfoResponse;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.GET;
    import retrofit2.http.Header;
    import retrofit2.http.POST;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface FortnitePublicService {
    @POST("/fortnite/api/game/v2/profile/{id}/client/{command}")
    Call<FortMcpResponse> clientCommand(@Path("command") String command, @Path("id") String accountId, @Query("profileId") String profileId, @Query("rvn") Integer currentProfileRevision, @Header("X-EpicGames-ProfileRevisions") String profileRevisionsMeta, @Body Object payload);

    @GET("/fortnite/api/game/v2/world/info")
    Call<WorldInfoResponse> pveWorldInfo();

    @GET("/fortnite/api/game/v2/privacy/account/{id}")
    Call<AccountPrivacyResponse> getAccountPrivacy(@Path("id") String id);

    @POST("/fortnite/api/game/v2/privacy/account/{id}")
    Call<AccountPrivacyResponse> setAccountPrivacy(@Path("id") String id, @Body AccountPrivacyResponse payload);

    @GET("/fortnite/api/storefront/v2/catalog")
    Call<FortCatalogResponse> storefrontCatalog();

    @GET("/fortnite/api/calendar/v1/timeline")
    Call<CalendarTimelineResponse> calendarTimeline();

    @GET("/fortnite/api/statsv2/account/{id}")
    Call<StatsV2Response> querySingleUserStats(@Path("id") String id, @Query("startTime") Long startTime, @Query("endTime") Long endTime);

    @POST("/fortnite/api/statsv2/query")
    Call<StatsV2Response[]> queryMultipleUserStats(@Body QueryMultipleUserStats payload);

    @GET("/fortnite/api/cloudstorage/user/{id}")
    Call<JsonObject[]> enumerateUserFiles(@Path("id") String id);

    @POST("/fortnite/api/game/v2/events/v2/processPendingRewards/{id}")
    Call<JsonElement[]> eventsProcessPendingRewards(@Path("id") String id);

    @GET("/fortnite/api/game/v2/tryPlayOnPlatform/account/{id}")
    Call<Boolean> tryPlayOnPlatform(@Path("id") String id, @Query("platform") String platform);

    @GET("/fortnite/api/game/v2/enabled_features")
    Call<JsonElement[]> enabledFeatures();

    @GET("/fortnite/api/storefront/v2/keychain")
    Call<String[]> storefrontKeychain(@Query("numKeysDownloaded") Integer numKeysDownloaded);

    @GET("/fortnite/api/receipts/v1/account/{id}/receipts")
    Call<Receipt[]> receipts(@Path("id") String id);
    }
  12. @Amrsatrio Amrsatrio revised this gist Jul 9, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion AccountPublicService.java
    Original file line number Diff line number Diff line change
    @@ -57,7 +57,7 @@ public interface AccountPublicService {
    Call<Void> killAuthSessions(@Field("killType") String killType);

    @GET("/account/api/public/account")
    Call<GameProfile[]> accountMultiple(@Query("accountId") List<String> ids);
    Call<GameProfile[]> queryUserInfo(@Query("accountId") List<String> ids);

    @GET("/account/api/public/account/{id}")
    Call<XGameProfile> queryUserInfo(@Path("id") String id);
  13. @Amrsatrio Amrsatrio renamed this gist Jul 9, 2019. 1 changed file with 0 additions and 0 deletions.
  14. @Amrsatrio Amrsatrio created this gist Jul 9, 2019.
    107 changes: 107 additions & 0 deletions Account Public Service Endpoints
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    package com.tb24.fn.network;

    import com.google.gson.JsonObject;
    import com.tb24.fn.model.DeviceAuth;
    import com.tb24.fn.model.ExchangeResponse;
    import com.tb24.fn.model.ExternalAuth;
    import com.tb24.fn.model.GameProfile;
    import com.tb24.fn.model.LoginResponse;
    import com.tb24.fn.model.QueryExternalIdMappingsByIdPayload;
    import com.tb24.fn.model.VerifyResponse;
    import com.tb24.fn.model.XGameProfile;

    import java.util.List;
    import java.util.Map;

    import retrofit2.Call;
    import retrofit2.http.Body;
    import retrofit2.http.DELETE;
    import retrofit2.http.Field;
    import retrofit2.http.FieldMap;
    import retrofit2.http.FormUrlEncoded;
    import retrofit2.http.GET;
    import retrofit2.http.Header;
    import retrofit2.http.POST;
    import retrofit2.http.Path;
    import retrofit2.http.Query;

    public interface AccountPublicService {
    /**
    * grant_type: authorization_code; fields: code
    * grant_type: client_credentials -- used to retrieve client ID without sign in
    * grant_type: device_auth; fields: account_id, device_id, secret
    * grant_type: exchange_code; fields: exchange_code
    * grant_type: external_auth; fields: external_auth_type, external_auth_token
    * grant_type: otp; fields: otp, challenge
    * grant_type: password; fields: username, password
    * grant_type: refresh_token; fields: refresh_token
    */
    @FormUrlEncoded
    @POST("/account/api/oauth/token")
    Call<LoginResponse> grantToken(@Header("Authorization") String auth, @Field("grant_type") String grantType, @FieldMap Map<String, String> fields, @Field("includePerms") Boolean includePerms);

    @GET("/account/api/oauth/exchange")
    Call<ExchangeResponse> exchangeToken();

    @GET("/account/api/oauth/verify")
    Call<VerifyResponse> verifyToken(@Query("includePerms") Boolean includePerms);

    @DELETE("/account/api/oauth/sessions/kill/{accessToken}")
    Call<Void> killAuthSession(@Path("accessToken") String accessToken);

    /**
    * @param killType OTHERS, ALL_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT, OTHERS_ACCOUNT_CLIENT_SERVICE
    */
    @FormUrlEncoded
    @DELETE("/account/api/oauth/sessions/kill")
    Call<Void> killAuthSessions(@Field("killType") String killType);

    @GET("/account/api/public/account")
    Call<GameProfile[]> accountMultiple(@Query("accountId") List<String> ids);

    @GET("/account/api/public/account/{id}")
    Call<XGameProfile> queryUserInfo(@Path("id") String id);

    @GET("/account/api/accounts/{id}/metadata")
    Call<JsonObject> queryUserMetaData(@Path("id") String id);

    @GET("/account/api/public/account/{accountId}/deviceAuth")
    Call<DeviceAuth[]> queryDeviceAuths(@Path("accountId") String accountId);

    @GET("/account/api/public/account/{accountId}/deviceAuth/{deviceId}")
    Call<DeviceAuth> queryDeviceAuths(@Path("accountId") String accountId, @Path("deviceId") String deviceId);

    @POST("/account/api/public/account/{accountId}/deviceAuth")
    Call<DeviceAuth> createDeviceAuth(@Path("accountId") String accountId, @Header("X-Epic-Device-Info") String deviceInfo);

    @DELETE("/account/api/public/account/{accountId}/deviceAuth/{deviceId}")
    Call<Void> deleteDeviceAuth(@Path("accountId") String accountId, @Path("deviceId") String deviceId);

    @GET("/account/api/public/account/{id}/externalAuths")
    Call<ExternalAuth[]> queryExternalAccounts(@Path("id") String id);

    @GET("/account/api/public/account/{id}/externalAuths/{type}")
    Call<ExternalAuth> queryExternalAccountsByType(@Path("id") String id, @Path("type") String type);

    // TODO @POST("/account/api/public/account/{id}/externalAuths")
    // JsonObject: authType, externalAuthToken
    // Call<ExternalAuth[]> addExternalAccount(@Path("id") String id, @Body AddExternalAccountPayload payload);

    @DELETE("/account/api/public/account/{id}/externalAuths/{type}")
    Call<Void> removeExternalAccount(@Path("id") String id, @Path("type") String type);

    @GET("/account/api/public/account/displayName/{name}")
    Call<GameProfile> queryUserIdFromDisplayName(@Path("name") String name);

    @GET("/account/api/public/account/email/{email}")
    Call<GameProfile> queryUserIdFromEmail(@Path("email") String email);

    @POST("/account/api/public/account/lookup/externalId")
    Call<Map<String, ExternalAuth>> queryExternalIdMappingsById(@Body QueryExternalIdMappingsByIdPayload payload);

    @GET("/account/api/public/account/lookup/externalAuth/{externalAuthType}/displayName/{displayName}")
    Call<GameProfile[]> queryExternalIdMappingsByDisplayName(@Path("externalAuthType") String externalAuthType, @Path("displayName") String displayName, @Query("caseInsensitive") Boolean caseInsensitive);

    @GET("/account/api/epicdomains/ssodomains")
    Call<String[]> querySSODomains();
    }