diff --git a/README.md b/README.md
index c0cc20a..a78d48b 100644
--- a/README.md
+++ b/README.md
@@ -87,7 +87,8 @@ Click the function names to open their complete docs on the docs site.
- [`getUserProgress()`](https://api-docs.retroachievements.org/v1/users/get-user-progress.html) - Get a user's progress on a list of specified games.
- [`getUserRecentAchievements()`](https://api-docs.retroachievements.org/v1/users/get-user-recent-achievements.html) - Get a list of achievements recently earned by the user.
- [`getUserRecentlyPlayedGames()`](https://api-docs.retroachievements.org/v1/users/get-user-recently-played-games.html) - Get a list of games a user has recently played.
-- [`getUserSummary()`](https://api-docs.retroachievements.org/v1/users/get-user-summary.html) - Get a user's profile metadata.
+- [`getUserSummary()`](https://api-docs.retroachievements.org/v1/users/get-user-summary.html) - Get a user's exhaustive profile metadata.
+- [`getUserProfile()`](https://api-docs.retroachievements.org/v1/users/users/profile.html) - Get a thin subset of a user's profile metadata.
### Games
@@ -133,15 +134,3 @@ Let us know about yours by [opening an issue](https://github.com/RetroAchievemen
## How to Contribute
Check out [CONTRIBUTING.md](https://github.com/RetroAchievements/api-js/blob/main/CONTRIBUTING.md) for how to get started.
-
-## Contributors
-
-
-
-
diff --git a/src/user/getUserProfile.test.ts b/src/user/getUserProfile.test.ts
new file mode 100644
index 0000000..142b070
--- /dev/null
+++ b/src/user/getUserProfile.test.ts
@@ -0,0 +1,79 @@
+import { http, HttpResponse } from "msw";
+import { setupServer } from "msw/node";
+
+import { apiBaseUrl } from "../utils/internal";
+import { buildAuthorization } from "../utils/public";
+import { getUserProfile } from "./getUserProfile";
+import type { GetUserProfileResponse } from "./models";
+
+const server = setupServer();
+
+describe("Function: getUserProfile", () => {
+ // MSW Setup
+ beforeAll(() => server.listen());
+ afterEach(() => server.resetHandlers());
+ afterAll(() => server.close());
+
+ it("is defined #sanity", () => {
+ // ASSERT
+ expect(getUserProfile).toBeDefined();
+ });
+
+ it("given a username, retrieves minimal user profile information about the user", async () => {
+ // ARRANGE
+ const authorization = buildAuthorization({
+ userName: "mockUserName",
+ webApiKey: "mockWebApiKey"
+ });
+
+ const mockResponse: GetUserProfileResponse = {
+ User: "MaxMilyin",
+ UserPic: "/UserPic/MaxMilyin.png",
+ MemberSince: "2016-01-02 00:43:04",
+ RichPresenceMsg:
+ "Playing ~Hack~ 11th Annual Vanilla Level Design Contest, The",
+ LastGameID: 19_504,
+ ContribCount: 0,
+ ContribYield: 0,
+ TotalPoints: 399_597,
+ TotalSoftcorePoints: 0,
+ TotalTruePoints: 1_599_212,
+ Permissions: 1,
+ Untracked: 0,
+ ID: 16_446,
+ UserWallActive: 1,
+ Motto: "Join me on Twitch! GameSquadSquad for live RA"
+ };
+
+ server.use(
+ http.get(`${apiBaseUrl}/API_GetUserProfile.php`, () =>
+ HttpResponse.json(mockResponse)
+ )
+ );
+
+ // ACT
+ const response = await getUserProfile(authorization, {
+ userName: "WCopeland"
+ });
+
+ // ASSERT
+ expect(response).toEqual({
+ user: "MaxMilyin",
+ userPic: "/UserPic/MaxMilyin.png",
+ memberSince: "2016-01-02 00:43:04",
+ richPresenceMsg:
+ "Playing ~Hack~ 11th Annual Vanilla Level Design Contest, The",
+ lastGameId: 19_504,
+ contribCount: 0,
+ contribYield: 0,
+ totalPoints: 399_597,
+ totalSoftcorePoints: 0,
+ totalTruePoints: 1_599_212,
+ permissions: 1,
+ untracked: false,
+ id: 16_446,
+ userWallActive: true,
+ motto: "Join me on Twitch! GameSquadSquad for live RA"
+ });
+ });
+});
diff --git a/src/user/getUserProfile.ts b/src/user/getUserProfile.ts
new file mode 100644
index 0000000..83a7470
--- /dev/null
+++ b/src/user/getUserProfile.ts
@@ -0,0 +1,55 @@
+import {
+ apiBaseUrl,
+ buildRequestUrl,
+ call,
+ serializeProperties
+} from "../utils/internal";
+import type { AuthObject } from "../utils/public";
+import type { GetUserProfileResponse, UserProfile } from "./models";
+
+/**
+ * A call to this function will retrieve summary information about
+ * a given user, targeted by username.
+ *
+ * @param authorization An object containing your userName and webApiKey.
+ * This can be constructed with `buildAuthorization()`.
+ *
+ * @param payload.userName The user for which to retrieve the summary for.
+ *
+ * @example
+ * ```
+ * const userSummary = await getUserProfile(
+ * authorization,
+ * { userName: "xelnia" }
+ * );
+ * ```
+ *
+ * @returns An object containing profile summary metadata about a target user.
+ */
+export const getUserProfile = async (
+ authorization: AuthObject,
+ payload: {
+ userName: string;
+ }
+): Promise => {
+ const { userName } = payload;
+
+ const url = buildRequestUrl(
+ apiBaseUrl,
+ "/API_GetUserProfile.php",
+ authorization,
+ { u: userName }
+ );
+
+ const rawResponse = await call({ url });
+
+ return serializeProperties(rawResponse, {
+ shouldCastToNumbers: [
+ "TotalPoints",
+ "TotalSoftcorePoints",
+ "TotalTruePoints",
+ "Permissions"
+ ],
+ shouldMapToBooleans: ["Untracked", "UserWallActive"]
+ });
+};
diff --git a/src/user/index.ts b/src/user/index.ts
index 08c853e..e6c1e38 100644
--- a/src/user/index.ts
+++ b/src/user/index.ts
@@ -7,6 +7,7 @@ export * from "./getUserCompletedGames";
export * from "./getUserCompletionProgress";
export * from "./getUserGameRankAndScore";
export * from "./getUserPoints";
+export * from "./getUserProfile";
export * from "./getUserProgress";
export * from "./getUserRecentAchievements";
export * from "./getUserRecentlyPlayedGames";
diff --git a/src/user/models/get-user-profile-response.model.ts b/src/user/models/get-user-profile-response.model.ts
new file mode 100644
index 0000000..e85c787
--- /dev/null
+++ b/src/user/models/get-user-profile-response.model.ts
@@ -0,0 +1,17 @@
+export interface GetUserProfileResponse {
+ User: string;
+ UserPic: string;
+ MemberSince: string;
+ RichPresenceMsg: string;
+ LastGameID: number;
+ ContribCount: number;
+ ContribYield: number;
+ TotalPoints: number;
+ TotalSoftcorePoints: number;
+ TotalTruePoints: number;
+ Permissions: number;
+ Untracked: number;
+ ID: number;
+ UserWallActive: number;
+ Motto: string;
+}
diff --git a/src/user/models/index.ts b/src/user/models/index.ts
index 8c623a3..b0f5ab6 100644
--- a/src/user/models/index.ts
+++ b/src/user/models/index.ts
@@ -8,6 +8,7 @@ export * from "./get-user-completed-games-response.model";
export * from "./get-user-completion-progress-response.model";
export * from "./get-user-game-rank-and-score-response.model";
export * from "./get-user-points-response.model";
+export * from "./get-user-profile-response.model";
export * from "./get-user-progress-response.model";
export * from "./get-user-recent-achievements-response.model";
export * from "./get-user-recently-played-games-response.model";
@@ -20,6 +21,7 @@ export * from "./user-completion-progress.model";
export * from "./user-completion-progress-entity.model";
export * from "./user-game-rank-and-score.model";
export * from "./user-points.model";
+export * from "./user-profile.model";
export * from "./user-progress.model";
export * from "./user-recent-achievement.model";
export * from "./user-recently-played-games.model";
diff --git a/src/user/models/user-profile.model.ts b/src/user/models/user-profile.model.ts
new file mode 100644
index 0000000..b447260
--- /dev/null
+++ b/src/user/models/user-profile.model.ts
@@ -0,0 +1,17 @@
+export interface UserProfile {
+ user: string;
+ userPic: string;
+ memberSince: string;
+ richPresenceMsg: string;
+ lastGameId: number;
+ contribCount: number;
+ contribYield: number;
+ totalPoints: number;
+ totalSoftcorePoints: number;
+ totalTruePoints: number;
+ permissions: number;
+ untracked: boolean;
+ id: number;
+ userWallActive: boolean;
+ motto: string;
+}