From 776791310b28097ae9dea2a2ff23fa9ca86888b2 Mon Sep 17 00:00:00 2001 From: Charlie Brinicombe <55358291+cbrinicombe13@users.noreply.github.com> Date: Mon, 12 Jan 2026 11:45:29 +0000 Subject: [PATCH 1/2] Add docs on user preferences --- .../endpoints/users/get-user-preferences.mdx | 3 + .../users/update-user-preferences.mdx | 3 + api-reference/openapi.yml | 1319 ++++++++++------- docs.json | 4 +- platform/emails.mdx | 16 +- platform/push-notifications.mdx | 11 + platform/users.mdx | 54 + ...et-user-notification-preferences-block.mdx | 36 + ...te-user-notification-preferences-block.mdx | 83 ++ 9 files changed, 987 insertions(+), 542 deletions(-) create mode 100644 api-reference/endpoints/users/get-user-preferences.mdx create mode 100644 api-reference/endpoints/users/update-user-preferences.mdx create mode 100644 snippets/get-user-notification-preferences-block.mdx create mode 100644 snippets/update-user-notification-preferences-block.mdx diff --git a/api-reference/endpoints/users/get-user-preferences.mdx b/api-reference/endpoints/users/get-user-preferences.mdx new file mode 100644 index 0000000..304d839 --- /dev/null +++ b/api-reference/endpoints/users/get-user-preferences.mdx @@ -0,0 +1,3 @@ +--- +openapi: get /users/{id}/preferences +--- diff --git a/api-reference/endpoints/users/update-user-preferences.mdx b/api-reference/endpoints/users/update-user-preferences.mdx new file mode 100644 index 0000000..41220f7 --- /dev/null +++ b/api-reference/endpoints/users/update-user-preferences.mdx @@ -0,0 +1,3 @@ +--- +openapi: patch /users/{id}/preferences +--- diff --git a/api-reference/openapi.yml b/api-reference/openapi.yml index 61133e5..4e0cea0 100644 --- a/api-reference/openapi.yml +++ b/api-reference/openapi.yml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: Trophy - version: '1.0.39' + version: "1.0.39" paths: # APPLICATION API ------------------------------------------------------- @@ -41,14 +41,14 @@ paths: type: string example: plan-type:premium,region:us-east responses: - '200': + "200": description: Successful operation content: application/json: schema: type: array items: - $ref: '#/components/schemas/AchievementWithStatsResponse' + $ref: "#/components/schemas/AchievementWithStatsResponse" examples: Successful operation: value: @@ -89,18 +89,18 @@ paths: userAttributes: - key: plan-type value: premium - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get all achievements and their completion stats security: - ApiKeyAuth: [] @@ -146,12 +146,12 @@ paths: type: string example: finish-onboarding responses: - '201': + "201": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/AchievementCompletionResponse' + $ref: "#/components/schemas/AchievementCompletionResponse" examples: Successful operation: value: @@ -163,7 +163,7 @@ paths: description: Complete the onboarding process. badgeUrl: https://example.com/badge.png key: finish-onboarding - achievedAt: '2021-01-01T00:00:00Z' + achievedAt: "2021-01-01T00:00:00Z" points: points-system-key: id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 @@ -175,31 +175,31 @@ paths: awards: - id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 awarded: 10 - date: '2021-01-01T00:00:00Z' + date: "2021-01-01T00:00:00Z" total: 10 trigger: id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 type: achievement achievementName: Finish onboarding points: 10 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Achievement Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Achievement Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Mark an achievement as completed security: - ApiKeyAuth: [] @@ -211,7 +211,7 @@ paths: type: object properties: user: - $ref: '#/components/schemas/UpsertedUser' + $ref: "#/components/schemas/UpsertedUser" description: The user that completed the achievement. required: - user @@ -303,12 +303,12 @@ paths: type: string example: e4296e4b-8493-4bd1-9c30-5a1a9ac4d78f responses: - '201': + "201": description: Created event content: application/json: schema: - $ref: '#/components/schemas/EventResponse' + $ref: "#/components/schemas/EventResponse" examples: Successful operation: value: @@ -323,14 +323,14 @@ paths: metricValue: 500 name: 500 words written description: Write 500 words in the app. - achievedAt: '2020-01-01T00:00:00Z' + achievedAt: "2020-01-01T00:00:00Z" currentStreak: length: 1 frequency: daily - started: '2025-04-02' - periodStart: '2025-03-31' - periodEnd: '2025-04-05' - expires: '2025-04-12' + started: "2025-04-02" + periodStart: "2025-03-31" + periodEnd: "2025-04-05" + expires: "2025-04-12" points: xp: id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 @@ -342,7 +342,7 @@ paths: awards: - id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 awarded: 10 - date: '2021-01-01T00:00:00Z' + date: "2021-01-01T00:00:00Z" total: 10 trigger: id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 @@ -364,28 +364,28 @@ paths: metricName: words written metricKey: words-written threshold: 10 - start: '2025-01-01' + start: "2025-01-01" end: null previousRank: null rank: 100 - '400': - description: 'Bad Request' + "400": + description: "Bad Request" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '401': - description: 'Unauthorized' + $ref: "#/components/schemas/ErrorBody" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Send a metric change event security: - ApiKeyAuth: [] @@ -397,7 +397,7 @@ paths: type: object properties: user: - $ref: '#/components/schemas/UpsertedUser' + $ref: "#/components/schemas/UpsertedUser" description: The user that triggered the event. value: type: number @@ -423,7 +423,7 @@ paths: user: email: user@example.com tz: Europe/London - id: '18' + id: "18" attributes: department: engineering role: developer @@ -485,15 +485,15 @@ paths: application/json: schema: type: object - $ref: '#/components/schemas/UpsertedUser' + $ref: "#/components/schemas/UpsertedUser" description: The user object. responses: - '201': + "201": description: Identified user content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" examples: Successful operation: value: @@ -501,29 +501,29 @@ paths: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer - '400': - description: 'Bad Request' + "400": + description: "Bad Request" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '401': - description: 'Unauthorized' + $ref: "#/components/schemas/ErrorBody" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" /users/{id}: servers: - url: https://api.trophy.so/v1 @@ -563,12 +563,12 @@ paths: security: - ApiKeyAuth: [] responses: - '200': + "200": description: Found user content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" examples: Successful operation: value: @@ -576,29 +576,29 @@ paths: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer - '400': - description: 'Bad Request' + "400": + description: "Bad Request" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '401': - description: 'Unauthorized' + $ref: "#/components/schemas/ErrorBody" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" put: description: Identify a user. operationId: users_identify @@ -654,7 +654,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UpdatedUser' + $ref: "#/components/schemas/UpdatedUser" description: The user object. example: email: user@example.com @@ -663,12 +663,12 @@ paths: department: engineering role: developer responses: - '200': + "200": description: Upserted user content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" examples: Successful operation: value: @@ -676,26 +676,26 @@ paths: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' - '400': - description: 'Bad Request' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" + "400": + description: "Bad Request" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '401': - description: 'Unauthorized' + $ref: "#/components/schemas/ErrorBody" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" patch: description: Update a user. operationId: users_update @@ -751,7 +751,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UpdatedUser' + $ref: "#/components/schemas/UpdatedUser" description: The user object. example: id: user-id @@ -761,12 +761,12 @@ paths: department: engineering role: developer responses: - '200': + "200": description: Updated user content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" examples: Successful operation: value: @@ -774,32 +774,214 @@ paths: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' - '400': - description: 'Bad Request' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" + "400": + description: "Bad Request" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'User Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "User Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '401': - description: 'Unauthorized' + $ref: "#/components/schemas/ErrorBody" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" + /users/{id}/preferences: + servers: + - url: https://api.trophy.so/v1 + description: Application API + get: + description: Get a user's notification preferences. + operationId: users_get_preferences + x-fern-server-name: api + tags: + - Users + x-codeSamples: + - lang: javascript + source: | + import { TrophyApiClient } from '@trophyso/node'; + + const trophy = new TrophyApiClient({ + apiKey: 'YOUR_API_KEY' + }); + + const response = await trophy.users.getPreferences("user-123"); + - lang: python + source: | + from trophy import TrophyApi + + client = TrophyApi(api_key='YOUR_API_KEY') + + response = client.users.get_preferences(id="user-123") + parameters: + - name: id + in: path + description: The user's ID in your database. + required: true + schema: + type: string + example: user-123 + responses: + "200": + description: Successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/UserPreferencesResponse" + examples: + Successful operation: + value: + notifications: + achievement_completed: + - email + - push + recap: + - email + reactivation: + - push + streak_reminder: + - email + - push + "401": + description: "Unauthorized" + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorBody" + "404": + description: "User not found" + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorBody" + summary: Get a user's preferences + security: + - ApiKeyAuth: [] + patch: + description: Update a user's notification preferences. + operationId: users_update_preferences + x-fern-server-name: api + tags: + - Users + x-codeSamples: + - lang: javascript + source: | + import { TrophyApiClient } from '@trophyso/node'; + + const trophy = new TrophyApiClient({ + apiKey: 'YOUR_API_KEY' + }); + + const response = await trophy.users.updatePreferences("user-123", { + notifications: { + recap: ["email"], + streak_reminder: [] + } + }); + - lang: python + source: | + from trophy import TrophyApi + + client = TrophyApi(api_key='YOUR_API_KEY') + + response = client.users.update_preferences( + id="user-123", + notifications={ + "recap": ["email"], + "streak_reminder": [] + } + ) + parameters: + - name: id + in: path + description: The user's ID in your database. + required: true + schema: + type: string + example: user-123 + responses: + "200": + description: Successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/UserPreferencesResponse" + examples: + Successful operation: + value: + notifications: + achievement_completed: + - email + - push + recap: + - email + reactivation: + - email + - push + streak_reminder: [] + "401": + description: "Unauthorized" + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorBody" + "404": + description: "User not found" + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorBody" + summary: Update a user's preferences + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateUserPreferencesRequest" + examples: + Disable streak reminders: + value: + notifications: + streak_reminder: [] + Email only for recaps: + value: + notifications: + recap: + - email + Enable all for achievements: + value: + notifications: + achievement_completed: + - email + - push /users/{id}/metrics: servers: - url: https://api.trophy.so/v1 @@ -836,14 +1018,14 @@ paths: type: string example: userId responses: - '200': + "200": description: Successful operation content: application/json: schema: type: array items: - $ref: '#/components/schemas/MetricResponse' + $ref: "#/components/schemas/MetricResponse" examples: Successful operation: value: @@ -856,45 +1038,45 @@ paths: - id: abe3120f-5ca9-4344-92c8-5b891643a04b trigger: metric name: Novice Writer - description: 'null' + description: "null" metricId: d01dcbcb-d51e-4c12-b054-dc811dcdc623 metricValue: 500 - achievedAt: '2021-01-01T00:00:00Z' + achievedAt: "2021-01-01T00:00:00Z" badgeUrl: https://example.com/badge1.png - id: 8a07f2d0-9c72-4de1-bf92-9530ae82b4b6 trigger: metric name: Intermediate Writer - description: 'null' + description: "null" metricId: d01dcbcb-d51e-4c12-b054-dc811dcdc623 metricValue: 1000 - achievedAt: '2021-01-02T00:00:00Z' + achievedAt: "2021-01-02T00:00:00Z" badgeUrl: https://example.com/badge2.png - id: 2090d038-aa04-4048-ab2e-e2b7bf2d3b9f trigger: metric name: Expert Writer - description: 'null' + description: "null" metricId: d01dcbcb-d51e-4c12-b054-dc811dcdc623 metricValue: 2000 achievedAt: null - badgeUrl: 'null' - '401': - description: 'Unauthorized' + badgeUrl: "null" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'User Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "User Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get all metrics for a user security: - ApiKeyAuth: [] @@ -941,12 +1123,12 @@ paths: type: string example: key responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/MetricResponse' + $ref: "#/components/schemas/MetricResponse" examples: Successful operation: value: @@ -961,13 +1143,13 @@ paths: name: Novice Writer metricId: d01dcbcb-d51e-4c12-b054-dc811dcdc623 metricValue: 500 - achievedAt: '2021-01-01T00:00:00Z' + achievedAt: "2021-01-01T00:00:00Z" - id: 8a07f2d0-9c72-4de1-bf92-9530ae82b4b6 trigger: metric name: Intermediate Writer metricId: d01dcbcb-d51e-4c12-b054-dc811dcdc623 metricValue: 1000 - achievedAt: '2021-01-02T00:00:00Z' + achievedAt: "2021-01-02T00:00:00Z" - id: 2090d038-aa04-4048-ab2e-e2b7bf2d3b9f trigger: metric name: Expert Writer @@ -975,24 +1157,24 @@ paths: metricValue: 2000 achievedAt: null badgeUrl: https://example.com/badge.png - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a single metric for a user security: - ApiKeyAuth: [] @@ -1066,7 +1248,7 @@ paths: schema: type: string format: date - example: '2024-01-01' + example: "2024-01-01" - name: endDate in: query description: The end date for the data range in YYYY-MM-DD format. The endDate must be after the startDate, and the date range must not exceed 400 days. @@ -1074,9 +1256,9 @@ paths: schema: type: string format: date - example: '2024-01-31' + example: "2024-01-31" responses: - '200': + "200": description: Successful operation content: application/json: @@ -1089,7 +1271,7 @@ paths: type: string format: date description: The date of the data point. For weekly or monthly aggregations, this is the first date of the period. - example: '2024-01-01' + example: "2024-01-01" total: type: number format: double @@ -1107,33 +1289,33 @@ paths: examples: Successful operation: value: - - date: '2024-01-01' + - date: "2024-01-01" total: 100 change: 100 - - date: '2024-01-02' + - date: "2024-01-02" total: 300 change: 200 - - date: '2024-01-03' + - date: "2024-01-03" total: 600 change: 300 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a summary of metric events over time security: - ApiKeyAuth: [] @@ -1200,17 +1382,17 @@ paths: required: false schema: type: string - enum: ['true'] - example: 'true' + enum: ["true"] + example: "true" responses: - '200': + "200": description: Successful operation content: application/json: schema: type: array items: - $ref: '#/components/schemas/UserAchievementWithStatsResponse' + $ref: "#/components/schemas/UserAchievementWithStatsResponse" examples: Successful operation: value: @@ -1218,7 +1400,7 @@ paths: name: Completed Onboarding trigger: api key: completed-onboarding - achievedAt: '2021-01-01T00:00:00Z' + achievedAt: "2021-01-01T00:00:00Z" badgeUrl: https://example.com/badge2.png completions: 100 rarity: 50 @@ -1229,7 +1411,7 @@ paths: metricValue: 500 metricName: words written name: Novice Writer - achievedAt: '2021-02-01T00:00:00Z' + achievedAt: "2021-02-01T00:00:00Z" badgeUrl: https://example.com/badge1.png completions: 100 rarity: 50 @@ -1238,28 +1420,28 @@ paths: key: 3-day-streak streakLength: 3 name: 3-Day Streak - achievedAt: '2021-03-01T00:00:00Z' + achievedAt: "2021-03-01T00:00:00Z" badgeUrl: https://example.com/badge2.png completions: 100 rarity: 50 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a user's achievements security: - ApiKeyAuth: [] @@ -1309,63 +1491,63 @@ paths: The number of past streak periods to include in the streakHistory field of the response. responses: - '200': + "200": description: Successful operation content: application/json: schema: type: object - $ref: '#/components/schemas/StreakResponse' + $ref: "#/components/schemas/StreakResponse" examples: Successful operation: value: length: 1 frequency: weekly - started: '2025-04-02' - periodStart: '2025-03-31' - periodEnd: '2025-04-05' - expires: '2025-04-12' + started: "2025-04-02" + periodStart: "2025-03-31" + periodEnd: "2025-04-05" + expires: "2025-04-12" rank: 5 streakHistory: - - periodStart: '2025-03-30' - periodEnd: '2025-04-05' + - periodStart: "2025-03-30" + periodEnd: "2025-04-05" length: 1 - - periodStart: '2025-04-06' - periodEnd: '2025-04-12' + - periodStart: "2025-04-06" + periodEnd: "2025-04-12" length: 2 - - periodStart: '2025-04-13' - periodEnd: '2025-04-19' + - periodStart: "2025-04-13" + periodEnd: "2025-04-19" length: 3 - - periodStart: '2025-04-20' - periodEnd: '2025-04-26' + - periodStart: "2025-04-20" + periodEnd: "2025-04-26" length: 0 - - periodStart: '2025-04-27' - periodEnd: '2025-05-03' + - periodStart: "2025-04-27" + periodEnd: "2025-05-03" length: 1 - - periodStart: '2025-05-04' - periodEnd: '2025-05-10' + - periodStart: "2025-05-04" + periodEnd: "2025-05-10" length: 2 - - periodStart: '2025-05-11' - periodEnd: '2025-05-17' + - periodStart: "2025-05-11" + periodEnd: "2025-05-17" length: 3 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a user's streak status security: - ApiKeyAuth: [] @@ -1403,38 +1585,38 @@ paths: type: array items: type: string - example: 'user-123,user-456,user-789' + example: "user-123,user-456,user-789" responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/BulkStreakResponse' + $ref: "#/components/schemas/BulkStreakResponse" examples: Successful operation: value: - userId: user-123 streakLength: 15 - extended: '2025-01-01T05:03:00Z' + extended: "2025-01-01T05:03:00Z" - userId: user-456 streakLength: 12 - extended: '2025-01-01T08:43:00Z' + extended: "2025-01-01T08:43:00Z" - userId: user-789 streakLength: 0 extended: null - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get the streak lengths of a list of users security: - ApiKeyAuth: [] @@ -1485,18 +1667,18 @@ paths: required: false schema: type: string - enum: ['active', 'longest'] - default: 'active' - example: 'active' + enum: ["active", "longest"] + default: "active" + example: "active" responses: - '200': + "200": description: Successful operation content: application/json: schema: type: array items: - $ref: '#/components/schemas/StreakRankingUser' + $ref: "#/components/schemas/StreakRankingUser" examples: Successful operation: value: @@ -1509,18 +1691,18 @@ paths: - userId: user-789 name: Charlie Brown streakLength: 8 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get top users by streak length security: - ApiKeyAuth: [] @@ -1575,12 +1757,12 @@ paths: maximum: 100 description: The number of recent point awards to return. responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/GetUserPointsResponse' + $ref: "#/components/schemas/GetUserPointsResponse" examples: Successful operation: value: @@ -1594,7 +1776,7 @@ paths: awards: - id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 awarded: 10 - date: '2021-01-01T00:00:00Z' + date: "2021-01-01T00:00:00Z" total: 100 trigger: id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 @@ -1602,24 +1784,24 @@ paths: points: 10 metricName: words written metricThreshold: 1000 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a user's points data security: - ApiKeyAuth: [] @@ -1693,7 +1875,7 @@ paths: schema: type: string format: date - example: '2024-01-01' + example: "2024-01-01" - name: endDate in: query description: The end date for the data range in YYYY-MM-DD format. The endDate must be after the startDate, and the date range must not exceed 400 days. @@ -1701,9 +1883,9 @@ paths: schema: type: string format: date - example: '2024-01-31' + example: "2024-01-31" responses: - '200': + "200": description: Successful operation content: application/json: @@ -1716,7 +1898,7 @@ paths: type: string format: date description: The date of the data point. For weekly or monthly aggregations, this is the first date of the period. - example: '2024-01-01' + example: "2024-01-01" total: type: number format: double @@ -1734,33 +1916,33 @@ paths: examples: Successful operation: value: - - date: '2024-01-01' + - date: "2024-01-01" total: 100 change: 100 - - date: '2024-01-02' + - date: "2024-01-02" total: 300 change: 200 - - date: '2024-01-03' + - date: "2024-01-03" total: 600 change: 300 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a summary of points events over time security: - ApiKeyAuth: [] @@ -1819,7 +2001,7 @@ paths: schema: type: string format: date - example: '2025-01-15' + example: "2025-01-15" - name: numEvents in: query description: The number of events to return in the history array. @@ -1831,12 +2013,12 @@ paths: maximum: 100 example: 10 responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/UserLeaderboardResponseWithHistory' + $ref: "#/components/schemas/UserLeaderboardResponseWithHistory" examples: Successful operation: value: @@ -1847,7 +2029,7 @@ paths: metricKey: words-written metricName: Words Written description: Compete weekly to see who writes the most words - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 100 breakdownAttribute: null @@ -1856,39 +2038,39 @@ paths: rank: 2 value: 4500 history: - - timestamp: '2025-01-15T10:30:00Z' + - timestamp: "2025-01-15T10:30:00Z" previousRank: null rank: 5 previousValue: null value: 1000 - - timestamp: '2025-01-15T14:15:00Z' + - timestamp: "2025-01-15T14:15:00Z" previousRank: 5 rank: 3 previousValue: 1000 value: 3000 - - timestamp: '2025-01-15T18:45:00Z' + - timestamp: "2025-01-15T18:45:00Z" previousRank: 3 rank: 2 previousValue: 3000 value: 4500 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'User or leaderboard not found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "User or leaderboard not found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a user's leaderboard data security: - ApiKeyAuth: [] @@ -1938,12 +2120,12 @@ paths: minimum: 1 example: 2024 responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/WrappedResponse' + $ref: "#/components/schemas/WrappedResponse" examples: Successful operation: value: @@ -1953,8 +2135,8 @@ paths: name: John Doe tz: America/New_York subscribeToEmails: true - created: '2024-01-15T10:30:00Z' - updated: '2024-06-20T14:45:00Z' + created: "2024-01-15T10:30:00Z" + updated: "2024-06-20T14:45:00Z" control: false attributes: plan-type: premium @@ -1964,7 +2146,7 @@ paths: weeksActive: 42 monthsActive: 11 mostActiveDay: - date: '2024-03-15' + date: "2024-03-15" metrics: words-written: name: Words Written @@ -1990,7 +2172,7 @@ paths: metricId: metric-123 metricValue: 500 metricName: Words Written - achievedAt: '2024-03-15T14:30:00Z' + achievedAt: "2024-03-15T14:30:00Z" completions: 150 rarity: 15 leaderboards: @@ -2002,16 +2184,16 @@ paths: metricKey: words-written metricName: Words Written description: Weekly writing competition - start: '2024-03-11' - end: '2024-03-17' + start: "2024-03-11" + end: "2024-03-17" maxParticipants: 100 runUnit: day runInterval: 7 rank: 3 value: 2500 mostActiveWeek: - start: '2024-03-11' - end: '2024-03-17' + start: "2024-03-11" + end: "2024-03-17" metrics: words-written: name: Words Written @@ -2080,34 +2262,34 @@ paths: metricId: metric-123 metricValue: 500 metricName: Words Written - achievedAt: '2024-03-15T14:30:00Z' + achievedAt: "2024-03-15T14:30:00Z" completions: 150 rarity: 15 leaderboards: {} longestStreak: length: 45 frequency: daily - periodStart: '2024-02-01' - periodEnd: '2024-03-17' - started: '2024-02-01' - '401': - description: 'Unauthorized' + periodStart: "2024-02-01" + periodEnd: "2024-03-17" + started: "2024-02-01" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'User not found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "User not found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a user's wrapped data security: - ApiKeyAuth: [] @@ -2159,12 +2341,12 @@ paths: type: string example: plan-type:premium,region:us-east responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/PointsSummaryResponse' + $ref: "#/components/schemas/PointsSummaryResponse" examples: Successful operation: value: @@ -2201,24 +2383,24 @@ paths: - from: 901 to: 1000 users: 0 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Not Found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Not Found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a breakdown of users by points security: - ApiKeyAuth: [] @@ -2258,12 +2440,12 @@ paths: type: string example: points-system-key responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/PointsSystemResponse' + $ref: "#/components/schemas/PointsSystemResponse" examples: Successful operation: value: @@ -2288,15 +2470,15 @@ paths: eventAttribute: key: source value: mobile-app - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" - id: 0040fe51-6bce-4b44-b0ad-bddc4e123536 type: streak points: 10 status: active streakLengthThreshold: 7 - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" - id: 0040fe51-6bce-4b44-b0ad-bddc4e123535 type: achievement points: 50 @@ -2306,20 +2488,20 @@ paths: userAttributes: - key: plan-type value: premium - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' - '401': - description: 'Unauthorized' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Points system not found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Points system not found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a points system with its triggers security: - ApiKeyAuth: [] @@ -2351,7 +2533,7 @@ paths: response = client.leaderboards.all() responses: - '200': + "200": description: Successful operation content: application/json: @@ -2359,12 +2541,12 @@ paths: type: array items: allOf: - - $ref: '#/components/schemas/LeaderboardResponse' + - $ref: "#/components/schemas/LeaderboardResponse" - type: object properties: status: type: string - enum: ['active', 'scheduled', 'finished'] + enum: ["active", "scheduled", "finished"] description: The status of the leaderboard. example: active required: @@ -2380,7 +2562,7 @@ paths: metricName: Words Written description: Compete weekly to see who writes the most words status: active - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 100 breakdownAttribute: null @@ -2394,24 +2576,24 @@ paths: pointsSystemName: Experience Points description: Overall ranking by XP earned status: active - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 50 breakdownAttribute: null runUnit: null runInterval: null - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get all active leaderboards security: - ApiKeyAuth: [] @@ -2515,14 +2697,14 @@ paths: schema: type: string format: date - example: '2025-01-15' + example: "2025-01-15" - name: userId in: query description: When provided, offset is relative to this user's position on the leaderboard. If the user is not found in the leaderboard, returns empty rankings array. required: false schema: type: string - example: 'user-123' + example: "user-123" - name: userAttributes in: query description: Attribute key and value to filter the rankings by, separated by a colon. For example, `city:London`. This parameter is required, and only valid for leaderboards with a breakdown attribute. @@ -2531,12 +2713,12 @@ paths: type: string example: city:London responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/LeaderboardResponseWithRankings' + $ref: "#/components/schemas/LeaderboardResponseWithRankings" examples: Successful operation: value: @@ -2550,7 +2732,7 @@ paths: pointsSystemName: null description: Compete weekly to see who writes the most words status: active - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 100 breakdownAttribute: null @@ -2569,24 +2751,24 @@ paths: userName: Charlie Brown rank: 3 value: 4200 - '401': - description: 'Unauthorized' + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '404': - description: 'Leaderboard not found' + $ref: "#/components/schemas/ErrorBody" + "404": + description: "Leaderboard not found" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Get a single leaderboard security: - ApiKeyAuth: [] @@ -2641,7 +2823,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/CreateStreakFreezesRequest' + $ref: "#/components/schemas/CreateStreakFreezesRequest" examples: Create freezes for multiple users: value: @@ -2650,12 +2832,12 @@ paths: - userId: user-456 - userId: user-123 responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/CreateStreakFreezesResponse' + $ref: "#/components/schemas/CreateStreakFreezesResponse" examples: Success with no issues: value: @@ -2675,24 +2857,24 @@ paths: - userId: user-456 level: warning reason: Would exceed maximum freeze limit - '400': - description: 'Bad Request' + "400": + description: "Bad Request" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '401': - description: 'Unauthorized' + $ref: "#/components/schemas/ErrorBody" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Create streak freezes for multiple users security: - ApiKeyAuth: [] @@ -2738,7 +2920,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/RestoreStreaksRequest' + $ref: "#/components/schemas/RestoreStreaksRequest" examples: Restore streaks for multiple users: value: @@ -2746,12 +2928,12 @@ paths: - id: user-123 - id: user-456 responses: - '200': + "200": description: Successful operation content: application/json: schema: - $ref: '#/components/schemas/RestoreStreaksResponse' + $ref: "#/components/schemas/RestoreStreaksResponse" examples: Success with no issues: value: @@ -2778,24 +2960,24 @@ paths: - userId: user-789 level: warning reason: Streak is already at maximum length - '400': - description: 'Bad Request' + "400": + description: "Bad Request" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '401': - description: 'Unauthorized' + $ref: "#/components/schemas/ErrorBody" + "401": + description: "Unauthorized" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' - '422': - description: 'Unprocessible Entity' + $ref: "#/components/schemas/ErrorBody" + "422": + description: "Unprocessible Entity" content: application/json: schema: - $ref: '#/components/schemas/ErrorBody' + $ref: "#/components/schemas/ErrorBody" summary: Restore streaks for multiple users security: - ApiKeyAuth: [] @@ -2813,13 +2995,13 @@ webhooks: properties: type: type: string - enum: ['achievement.completed'] + enum: ["achievement.completed"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user who completed the achievement. achievement: - $ref: '#/components/schemas/UserAchievementResponse' + $ref: "#/components/schemas/UserAchievementResponse" description: The achievement completion that occurred. required: - type @@ -2834,8 +3016,8 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer @@ -2845,11 +3027,11 @@ webhooks: trigger: api description: null key: completed-onboarding - achievedAt: '2021-01-01T00:00:00Z' + achievedAt: "2021-01-01T00:00:00Z" badgeUrl: https://example.com/badge2.png responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. streak.started: post: @@ -2864,13 +3046,13 @@ webhooks: properties: type: type: string - enum: ['streak.started'] + enum: ["streak.started"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user who started the streak. streak: - $ref: '#/components/schemas/BaseStreakResponse' + $ref: "#/components/schemas/BaseStreakResponse" description: The streak that was started. required: - type @@ -2885,24 +3067,24 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer streak: length: 1 frequency: daily - periodStart: '2025-04-02' - periodEnd: '2025-04-02' - started: '2025-04-02' - expires: '2025-04-03' + periodStart: "2025-04-02" + periodEnd: "2025-04-02" + started: "2025-04-02" + expires: "2025-04-03" freezes: 0 maxFreezes: 3 freezeAutoEarnInterval: 7 freezeAutoEarnAmount: 1 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. streak.extended: post: @@ -2917,13 +3099,13 @@ webhooks: properties: type: type: string - enum: ['streak.extended'] + enum: ["streak.extended"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user who extended the streak. streak: - $ref: '#/components/schemas/BaseStreakResponse' + $ref: "#/components/schemas/BaseStreakResponse" description: The streak that was extended. required: - type @@ -2938,24 +3120,24 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer streak: length: 2 frequency: daily - periodStart: '2025-04-03' - periodEnd: '2025-04-03' - started: '2025-04-02' - expires: '2025-04-05' + periodStart: "2025-04-03" + periodEnd: "2025-04-03" + started: "2025-04-02" + expires: "2025-04-05" freezes: 0 maxFreezes: 3 freezeAutoEarnInterval: 7 freezeAutoEarnAmount: 1 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. streak.lost: post: @@ -2970,10 +3152,10 @@ webhooks: properties: type: type: string - enum: ['streak.lost'] + enum: ["streak.lost"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user who lost the streak. length: type: integer @@ -2991,14 +3173,14 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer length: 7 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. streak.freeze_consumed: post: @@ -3013,10 +3195,10 @@ webhooks: properties: type: type: string - enum: ['streak.freeze_consumed'] + enum: ["streak.freeze_consumed"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user whose streak freeze was consumed. consumed: type: integer @@ -3038,15 +3220,15 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer consumed: 1 freezes: 2 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. streak.freeze_earned: post: @@ -3061,10 +3243,10 @@ webhooks: properties: type: type: string - enum: ['streak.freeze_earned'] + enum: ["streak.freeze_earned"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user who earned streak freezes. earned: type: integer @@ -3086,15 +3268,15 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer earned: 1 freezes: 2 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. points.changed: post: @@ -3109,13 +3291,13 @@ webhooks: properties: type: type: string - enum: ['points.changed'] + enum: ["points.changed"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user whose points increased or decreased. points: - $ref: '#/components/schemas/GetUserPointsResponse' + $ref: "#/components/schemas/GetUserPointsResponse" description: The user's points after the event. required: - type @@ -3130,8 +3312,8 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer @@ -3146,7 +3328,7 @@ webhooks: awards: - id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 awarded: 10 - date: '2021-01-01T00:00:00Z' + date: "2021-01-01T00:00:00Z" total: 100 trigger: id: 0040fe51-6bce-4b44-b0ad-bddc4e123534 @@ -3155,7 +3337,7 @@ webhooks: metricName: words written metricThreshold: 1000 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. leaderboard.started: post: @@ -3170,10 +3352,10 @@ webhooks: properties: type: type: string - enum: ['leaderboard.started'] + enum: ["leaderboard.started"] description: The webhook event type. leaderboard: - $ref: '#/components/schemas/LeaderboardResponseWithRankings' + $ref: "#/components/schemas/LeaderboardResponseWithRankings" description: The leaderboard run that started and its initial rankings. required: - type @@ -3193,7 +3375,7 @@ webhooks: pointsSystemName: null description: Compete weekly to see who writes the most words status: active - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 100 breakdownAttribute: null @@ -3205,7 +3387,7 @@ webhooks: rank: 1 value: 1 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. leaderboard.changed: post: @@ -3220,10 +3402,10 @@ webhooks: properties: type: type: string - enum: ['leaderboard.changed'] + enum: ["leaderboard.changed"] description: The webhook event type. leaderboard: - $ref: '#/components/schemas/LeaderboardResponseWithRankings' + $ref: "#/components/schemas/LeaderboardResponseWithRankings" description: The leaderboard run that changed. required: - type @@ -3243,7 +3425,7 @@ webhooks: pointsSystemName: null description: Compete weekly to see who writes the most words status: active - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 100 breakdownAttribute: null @@ -3263,7 +3445,7 @@ webhooks: rank: 3 value: 4 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. leaderboard.finished: post: @@ -3278,10 +3460,10 @@ webhooks: properties: type: type: string - enum: ['leaderboard.finished'] + enum: ["leaderboard.finished"] description: The webhook event type. leaderboard: - $ref: '#/components/schemas/LeaderboardResponseWithRankings' + $ref: "#/components/schemas/LeaderboardResponseWithRankings" description: The leaderboard run that finished and its final rankings. required: - type @@ -3301,7 +3483,7 @@ webhooks: pointsSystemName: null description: Compete weekly to see who writes the most words status: active - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 100 breakdownAttribute: null @@ -3321,7 +3503,7 @@ webhooks: rank: 3 value: 4 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. leaderboard.rank_changed: post: @@ -3336,13 +3518,13 @@ webhooks: properties: type: type: string - enum: ['leaderboard.rank_changed'] + enum: ["leaderboard.rank_changed"] description: The webhook event type. user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user whose rank changed. leaderboard: - $ref: '#/components/schemas/WebhookUserLeaderboardResponse' + $ref: "#/components/schemas/WebhookUserLeaderboardResponse" description: The user's leaderboard data that changed. required: - type @@ -3357,8 +3539,8 @@ webhooks: email: user@example.com tz: Europe/London subscribedToEmails: true - created: '2021-01-01T00:00:00Z' - updated: '2021-01-01T00:00:00Z' + created: "2021-01-01T00:00:00Z" + updated: "2021-01-01T00:00:00Z" attributes: department: engineering role: developer @@ -3370,7 +3552,7 @@ webhooks: metricKey: words-written metricName: Words Written description: Compete weekly to see who writes the most words - start: '2025-01-01' + start: "2025-01-01" end: null maxParticipants: 100 breakdownAttribute: null @@ -3381,7 +3563,7 @@ webhooks: previousRank: 1 previousValue: 4500 responses: - '200': + "200": description: Return a 200 status to indicate the webhook was received and processed. components: schemas: @@ -3407,30 +3589,30 @@ components: type: integer description: The length of the user's current streak. frequency: - $ref: '#/components/schemas/StreakFrequency' + $ref: "#/components/schemas/StreakFrequency" description: The frequency of the streak. started: type: - string - - 'null' + - "null" format: date description: The date the streak started. periodStart: type: - string - - 'null' + - "null" format: date description: The start date of the current streak period. periodEnd: type: - string - - 'null' + - "null" format: date description: The end date of the current streak period. expires: type: - string - - 'null' + - "null" format: date description: The date the streak will expire if the user does not increment a metric. freezes: @@ -3466,7 +3648,7 @@ components: extended: type: - string - - 'null' + - "null" description: The timestamp the streak was extended, as a string. Null if the streak is not active. required: - userId @@ -3477,7 +3659,7 @@ components: type: object description: An object representing the user's streak after sending a metric event. allOf: - - $ref: '#/components/schemas/BaseStreakResponse' + - $ref: "#/components/schemas/BaseStreakResponse" - type: object properties: extended: @@ -3490,7 +3672,7 @@ components: type: object description: An object representing the user's streak. allOf: - - $ref: '#/components/schemas/BaseStreakResponse' + - $ref: "#/components/schemas/BaseStreakResponse" - type: object properties: streakHistory: @@ -3507,12 +3689,12 @@ components: type: string format: date description: The date this streak period started. - example: '2025-03-31' + example: "2025-03-31" periodEnd: type: string format: date description: The date this streak period ended. - example: '2025-04-05' + example: "2025-04-05" length: type: integer description: The length of the user's streak during this period. @@ -3528,7 +3710,7 @@ components: rank: type: - integer - - 'null' + - "null" description: The user's rank across all users. Null if the user has no active streak. example: 5 required: @@ -3543,7 +3725,7 @@ components: type: type: string description: The type of trigger - enum: ['metric', 'achievement', 'streak', 'time', 'user_creation'] + enum: ["metric", "achievement", "streak", "time", "user_creation"] points: type: integer description: The points awarded by this trigger. @@ -3561,7 +3743,7 @@ components: description: If the trigger has type 'achievement', the name of the achievement timeUnit: type: string - enum: ['hour', 'day'] + enum: ["hour", "day"] description: If the trigger has type 'time', the unit of time after which to award points timeInterval: type: integer @@ -3583,7 +3765,7 @@ components: type: integer description: The user's total points after this award occurred. trigger: - $ref: '#/components/schemas/PointsTrigger' + $ref: "#/components/schemas/PointsTrigger" GetUserPointsResponse: title: GetUserPointsResponse type: object @@ -3600,17 +3782,17 @@ components: description: type: - string - - 'null' + - "null" description: The description of the points system badgeUrl: type: - string - - 'null' + - "null" description: The URL of the badge image for the points system maxPoints: type: - number - - 'null' + - "null" description: The maximum number of points a user can be awarded in this points system total: type: integer @@ -3619,7 +3801,7 @@ components: type: array description: Array of trigger awards that added points. items: - $ref: '#/components/schemas/PointsAward' + $ref: "#/components/schemas/PointsAward" required: - id - key @@ -3648,13 +3830,13 @@ components: example: weekly-words rankBy: type: string - enum: ['points', 'streak', 'metric'] + enum: ["points", "streak", "metric"] description: What the leaderboard ranks by. example: metric breakdownAttribute: type: - string - - 'null' + - "null" description: The key of the attribute to break down this leaderboard by. example: country metricKey: @@ -3676,21 +3858,21 @@ components: description: type: - string - - 'null' + - "null" description: The user-facing description of the leaderboard. example: Compete weekly to see who writes the most words start: type: string format: date description: The start date of the leaderboard in YYYY-MM-DD format. - example: '2025-01-01' + example: "2025-01-01" end: type: - string - - 'null' + - "null" format: date description: The end date of the leaderboard in YYYY-MM-DD format, or null if it runs forever. - example: '2025-12-31' + example: "2025-12-31" maxParticipants: type: integer description: The maximum number of participants in the leaderboard. @@ -3698,14 +3880,14 @@ components: runUnit: type: - string - - 'null' - enum: ['day', 'month', 'year', null] + - "null" + enum: ["day", "month", "year", null] description: The repetition type for recurring leaderboards, or null for one-time leaderboards. example: day runInterval: type: - integer - - 'null' + - "null" description: The interval between repetitions, relative to the start date and repetition type. Null for one-time leaderboards. example: 7 required: @@ -3725,19 +3907,19 @@ components: title: LeaderboardResponseWithRankings type: object allOf: - - $ref: '#/components/schemas/LeaderboardResponse' + - $ref: "#/components/schemas/LeaderboardResponse" - type: object properties: status: type: string - enum: ['active', 'scheduled', 'finished'] + enum: ["active", "scheduled", "finished"] description: The status of the leaderboard. example: active rankings: type: array description: Array of user rankings for the leaderboard. items: - $ref: '#/components/schemas/LeaderboardRanking' + $ref: "#/components/schemas/LeaderboardRanking" required: - rankings - status @@ -3745,7 +3927,7 @@ components: title: MetricEventPointsResponse type: object allOf: - - $ref: '#/components/schemas/GetUserPointsResponse' + - $ref: "#/components/schemas/GetUserPointsResponse" - type: object properties: added: @@ -3758,31 +3940,31 @@ components: title: MetricEventLeaderboardResponse type: object allOf: - - $ref: '#/components/schemas/LeaderboardResponse' + - $ref: "#/components/schemas/LeaderboardResponse" - type: object properties: start: type: string format: date description: The start date of the current run of the leaderboard. - example: '2025-01-01' + example: "2025-01-01" end: type: - string - - 'null' + - "null" format: date description: The end date of the current run of the leaderboard, or null if the run never ends. - example: '2025-12-31' + example: "2025-12-31" rank: type: - integer - - 'null' + - "null" description: The user's rank in the leaderboard, or null if the user is not on the leaderboard. example: 100 previousRank: type: - integer - - 'null' + - "null" description: The user's rank in the leaderboard before the event, or null if the user was not on the leaderboard before the event. example: 100 threshold: @@ -3811,17 +3993,17 @@ components: description: The name of this achievement. trigger: type: string - enum: ['metric', 'streak', 'api'] + enum: ["metric", "streak", "api"] description: The trigger of the achievement. description: type: - string - - 'null' + - "null" description: The description of this achievement. badgeUrl: type: - string - - 'null' + - "null" description: >- The URL of the badge image for the achievement, if one has been uploaded. @@ -3884,13 +4066,13 @@ components: title: UserAchievementResponse type: object allOf: - - $ref: '#/components/schemas/AchievementResponse' + - $ref: "#/components/schemas/AchievementResponse" - type: object properties: achievedAt: type: - string - - 'null' + - "null" format: date-time description: The date and time the achievement was completed, in ISO 8601 format. Null if the achievement has not been completed. required: @@ -3899,13 +4081,13 @@ components: title: UserAchievementWithStatsResponse type: object allOf: - - $ref: '#/components/schemas/AchievementWithStatsResponse' + - $ref: "#/components/schemas/AchievementWithStatsResponse" - type: object properties: achievedAt: type: - string - - 'null' + - "null" format: date-time description: The date and time the achievement was completed, in ISO 8601 format. Null if the achievement has not been completed. required: @@ -3914,7 +4096,7 @@ components: title: AchievementWithStatsResponse type: object allOf: - - $ref: '#/components/schemas/AchievementResponse' + - $ref: "#/components/schemas/AchievementResponse" - type: object properties: completions: @@ -3944,7 +4126,7 @@ components: description: The name of the metric. example: Words written status: - $ref: '#/components/schemas/MetricStatus' + $ref: "#/components/schemas/MetricStatus" description: The status of the metric. current: type: number @@ -3954,7 +4136,7 @@ components: achievements: type: array items: - $ref: '#/components/schemas/UserAchievementResponse' + $ref: "#/components/schemas/UserAchievementResponse" description: >- A list of the metric's achievements and the user's progress towards each. @@ -3981,18 +4163,18 @@ components: tz: type: - string - - 'null' + - "null" description: The user's timezone (used for email scheduling). example: Europe/London deviceTokens: type: - array - - 'null' + - "null" description: The user's device tokens, used for push notifications. items: type: string description: The device token. - example: ['token1', 'token2'] + example: ["token1", "token2"] subscribeToEmails: type: boolean default: true @@ -4011,7 +4193,7 @@ components: type: object description: An object with editable user fields. allOf: - - $ref: '#/components/schemas/UpdatedUser' + - $ref: "#/components/schemas/UpdatedUser" - type: object properties: id: @@ -4032,30 +4214,30 @@ components: email: type: - string - - 'null' + - "null" description: The user's email address. example: user@example.com name: type: - string - - 'null' + - "null" description: The name of the user. example: John Doe tz: type: - string - - 'null' + - "null" description: The user's timezone. example: Europe/London deviceTokens: type: - array - - 'null' + - "null" description: The user's device tokens. items: type: string description: The device token. - example: ['token1', 'token2'] + example: ["token1", "token2"] subscribeToEmails: type: boolean description: Whether the user is opted into receiving Trophy-powered emails. @@ -4076,12 +4258,12 @@ components: type: string format: date-time description: The date and time the user was created, in ISO 8601 format. - example: '2021-01-01T00:00:00Z' + example: "2021-01-01T00:00:00Z" updated: type: string format: date-time description: The date and time the user was last updated, in ISO 8601 format. - example: '2021-01-01T00:00:00Z' + example: "2021-01-01T00:00:00Z" required: - id - email @@ -4092,6 +4274,63 @@ components: - control - created - updated + NotificationChannel: + title: NotificationChannel + type: string + enum: + - email + - push + description: A notification delivery channel. + NotificationType: + title: NotificationType + type: string + enum: + - achievement_completed + - recap + - reactivation + - streak_reminder + description: A type of notification that can be configured. + NotificationPreferences: + title: NotificationPreferences + type: object + description: Notification preferences for each notification type. + properties: + achievement_completed: + type: array + items: + $ref: "#/components/schemas/NotificationChannel" + description: Channels to receive achievement completion notifications on. + recap: + type: array + items: + $ref: "#/components/schemas/NotificationChannel" + description: Channels to receive recap notifications on. + reactivation: + type: array + items: + $ref: "#/components/schemas/NotificationChannel" + description: Channels to receive reactivation notifications on. + streak_reminder: + type: array + items: + $ref: "#/components/schemas/NotificationChannel" + description: Channels to receive streak reminder notifications on. + UserPreferencesResponse: + title: UserPreferencesResponse + type: object + description: A user's preferences. + properties: + notifications: + $ref: "#/components/schemas/NotificationPreferences" + required: + - notifications + UpdateUserPreferencesRequest: + title: UpdateUserPreferencesRequest + type: object + description: Request body for updating user preferences. + properties: + notifications: + $ref: "#/components/schemas/NotificationPreferences" ErrorBody: title: ErrorBody type: object @@ -4109,11 +4348,11 @@ components: description: The unique ID of the completion. example: 0040fe51-6bce-4b44-b0ad-bddc4e123534 achievement: - $ref: '#/components/schemas/UserAchievementResponse' + $ref: "#/components/schemas/UserAchievementResponse" points: type: object additionalProperties: - $ref: '#/components/schemas/MetricEventPointsResponse' + $ref: "#/components/schemas/MetricEventPointsResponse" description: >- A map of points systems by key that were affected by this achievement completion. required: @@ -4140,22 +4379,22 @@ components: achievements: type: array items: - $ref: '#/components/schemas/UserAchievementResponse' + $ref: "#/components/schemas/UserAchievementResponse" description: Achievements completed as a result of this event. currentStreak: - $ref: '#/components/schemas/MetricEventStreakResponse' + $ref: "#/components/schemas/MetricEventStreakResponse" description: >- The user's current streak. points: type: object additionalProperties: - $ref: '#/components/schemas/MetricEventPointsResponse' + $ref: "#/components/schemas/MetricEventPointsResponse" description: >- A map of points systems by key. Only contains points systems that were affected by the event. leaderboards: type: object additionalProperties: - $ref: '#/components/schemas/MetricEventLeaderboardResponse' + $ref: "#/components/schemas/MetricEventLeaderboardResponse" description: >- A map of leaderboards by key. Only contains leaderboards that were affected by the event. idempotencyKey: @@ -4198,7 +4437,7 @@ components: to the greatest number of points a user has, rounded up to the nearest power of 10. items: - $ref: '#/components/schemas/PointsRange' + $ref: "#/components/schemas/PointsRange" PointsTriggerResponse: title: PointsTriggerResponse type: object @@ -4208,14 +4447,14 @@ components: description: The unique ID of the trigger. type: type: string - enum: ['metric', 'achievement', 'streak', 'time', 'user_creation'] + enum: ["metric", "achievement", "streak", "time", "user_creation"] description: The type of trigger. points: type: integer description: The points awarded by this trigger. status: type: string - enum: ['active', 'archived'] + enum: ["active", "archived"] description: The status of the trigger. achievementId: type: string @@ -4237,7 +4476,7 @@ components: description: The name of the achievement associated with this trigger, if the trigger is an achievement. timeUnit: type: string - enum: ['hour', 'day'] + enum: ["hour", "day"] description: The time unit of the trigger, if the trigger is a time interval. timeInterval: type: integer @@ -4302,23 +4541,23 @@ components: description: type: - string - - 'null' + - "null" description: The description of the points system. badgeUrl: type: - string - - 'null' + - "null" description: The URL of the badge image for the points system, if one has been uploaded. maxPoints: type: - number - - 'null' + - "null" description: The maximum number of points a user can be awarded in this points system triggers: type: array description: Array of active triggers for this points system. items: - $ref: '#/components/schemas/PointsTriggerResponse' + $ref: "#/components/schemas/PointsTriggerResponse" required: - id - name @@ -4338,7 +4577,7 @@ components: name: type: - string - - 'null' + - "null" description: The name of the user. May be null if no name is set. example: Alice Johnson streakLength: @@ -4361,7 +4600,7 @@ components: userName: type: - string - - 'null' + - "null" description: The name of the user. May be null if no name is set. example: Alice Johnson rank: @@ -4386,29 +4625,29 @@ components: type: string format: date-time description: The timestamp when the event occurred. - example: '2025-01-15T10:30:00Z' + example: "2025-01-15T10:30:00Z" previousRank: type: - integer - - 'null' + - "null" description: The user's rank before this event, or null if they were not on the leaderboard. example: 5 rank: type: - integer - - 'null' + - "null" description: The user's rank after this event, or null if they are no longer on the leaderboard. example: 3 previousValue: type: - integer - - 'null' + - "null" description: The user's value before this event, or null if they were not on the leaderboard. example: 1000 value: type: - integer - - 'null' + - "null" description: The user's value after this event, or null if they are no longer on the leaderboard. example: 3000 required: @@ -4422,19 +4661,19 @@ components: type: object description: A user's data for a specific leaderboard including rank, value, and history. allOf: - - $ref: '#/components/schemas/LeaderboardResponse' + - $ref: "#/components/schemas/LeaderboardResponse" - type: object properties: rank: type: - integer - - 'null' + - "null" description: The user's current rank in this leaderboard. Null if the user is not on the leaderboard. example: 2 value: type: - integer - - 'null' + - "null" description: The user's current value in this leaderboard. Null if the user is not on the leaderboard. example: 4500 required: @@ -4445,13 +4684,13 @@ components: type: object description: A user's data for a specific leaderboard including rank, value, and history. allOf: - - $ref: '#/components/schemas/UserLeaderboardResponse' + - $ref: "#/components/schemas/UserLeaderboardResponse" - type: object properties: history: type: array items: - $ref: '#/components/schemas/LeaderboardEvent' + $ref: "#/components/schemas/LeaderboardEvent" description: An array of events showing the user's rank and value changes over time. required: - history @@ -4460,19 +4699,19 @@ components: type: object description: A user's data for a specific leaderboard including rank, value, and history. allOf: - - $ref: '#/components/schemas/UserLeaderboardResponse' + - $ref: "#/components/schemas/UserLeaderboardResponse" - type: object properties: previousRank: type: - integer - - 'null' + - "null" description: The user's rank before this event, or null if they were not on the leaderboard. example: 5 previousValue: type: - integer - - 'null' + - "null" description: The user's value before this event, or null if they were not on the leaderboard. example: 1000 required: @@ -4507,7 +4746,7 @@ components: issues: type: array items: - $ref: '#/components/schemas/BulkInsertIssue' + $ref: "#/components/schemas/BulkInsertIssue" description: Array of issues encountered during freeze creation. required: - issues @@ -4551,7 +4790,7 @@ components: issues: type: array items: - $ref: '#/components/schemas/BulkInsertIssue' + $ref: "#/components/schemas/BulkInsertIssue" description: Array of issues encountered during streak restoration. required: - restoredUsers @@ -4592,7 +4831,7 @@ components: units: type: - string - - 'null' + - "null" description: The units of the metric. example: words currentTotal: @@ -4624,7 +4863,7 @@ components: units: type: - string - - 'null' + - "null" description: The units of the metric. currentTotal: type: number @@ -4657,7 +4896,7 @@ components: description: type: - string - - 'null' + - "null" description: The description of the points system. example: Points earned through activity currentTotal: @@ -4691,29 +4930,29 @@ components: description: The length of the streak. example: 45 frequency: - $ref: '#/components/schemas/StreakFrequency' + $ref: "#/components/schemas/StreakFrequency" description: The frequency of the streak. periodStart: type: - string - - 'null' + - "null" format: date description: The start date of the streak period. - example: '2024-02-01' + example: "2024-02-01" periodEnd: type: - string - - 'null' + - "null" format: date description: The end date of the streak period. - example: '2024-03-17' + example: "2024-03-17" started: type: - string - - 'null' + - "null" format: date description: The date the streak started. - example: '2024-02-01' + example: "2024-02-01" required: - length - frequency @@ -4728,22 +4967,22 @@ components: metrics: type: object additionalProperties: - $ref: '#/components/schemas/WrappedMetric' + $ref: "#/components/schemas/WrappedMetric" description: The user's metrics during this period, keyed by metric key. points: type: object additionalProperties: - $ref: '#/components/schemas/WrappedPoints' + $ref: "#/components/schemas/WrappedPoints" description: The user's points during this period, keyed by points system key. achievements: type: array items: - $ref: '#/components/schemas/UserAchievementResponse' + $ref: "#/components/schemas/UserAchievementResponse" description: Achievements completed during this period. leaderboards: type: object additionalProperties: - $ref: '#/components/schemas/UserLeaderboardResponse' + $ref: "#/components/schemas/UserLeaderboardResponse" description: The user's best leaderboard rankings during this period, keyed by leaderboard key. required: - metrics @@ -4755,14 +4994,14 @@ components: type: object description: The user's most active day during the year. allOf: - - $ref: '#/components/schemas/WrappedActivityPeriod' + - $ref: "#/components/schemas/WrappedActivityPeriod" - type: object properties: date: type: string format: date description: The date of the most active day in YYYY-MM-DD format. - example: '2024-03-15' + example: "2024-03-15" required: - date WrappedMostActiveWeek: @@ -4770,19 +5009,19 @@ components: type: object description: The user's most active week during the year. allOf: - - $ref: '#/components/schemas/WrappedActivityPeriod' + - $ref: "#/components/schemas/WrappedActivityPeriod" - type: object properties: start: type: string format: date description: The start date of the most active week in YYYY-MM-DD format. - example: '2024-03-11' + example: "2024-03-11" end: type: string format: date description: The end date of the most active week in YYYY-MM-DD format. - example: '2024-03-17' + example: "2024-03-17" required: - start - end @@ -4791,7 +5030,7 @@ components: type: object description: The user's most active month during the year. allOf: - - $ref: '#/components/schemas/WrappedActivityPeriod' + - $ref: "#/components/schemas/WrappedActivityPeriod" - type: object properties: month: @@ -4807,11 +5046,11 @@ components: type: object description: The user's activity data for the entire year. allOf: - - $ref: '#/components/schemas/WrappedActivityPeriod' + - $ref: "#/components/schemas/WrappedActivityPeriod" - type: object properties: longestStreak: - $ref: '#/components/schemas/WrappedStreak' + $ref: "#/components/schemas/WrappedStreak" description: The user's longest streak during the year. required: - longestStreak @@ -4833,16 +5072,16 @@ components: description: The number of months the user was active during the year. example: 11 mostActiveDay: - $ref: '#/components/schemas/WrappedMostActiveDay' + $ref: "#/components/schemas/WrappedMostActiveDay" description: Data about the user's most active day. mostActiveWeek: - $ref: '#/components/schemas/WrappedMostActiveWeek' + $ref: "#/components/schemas/WrappedMostActiveWeek" description: Data about the user's most active week. mostActiveMonth: - $ref: '#/components/schemas/WrappedMostActiveMonth' + $ref: "#/components/schemas/WrappedMostActiveMonth" description: Data about the user's most active month. entireYear: - $ref: '#/components/schemas/WrappedEntireYear' + $ref: "#/components/schemas/WrappedEntireYear" description: Data about the user's activity for the entire year. required: - daysActive @@ -4858,10 +5097,10 @@ components: description: A user's year-in-review wrapped data including activity summaries, metrics, points, achievements, streaks, and leaderboard rankings. properties: user: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: The user's profile information. activity: - $ref: '#/components/schemas/WrappedActivity' + $ref: "#/components/schemas/WrappedActivity" description: The user's activity data for the wrapped year. required: - user diff --git a/docs.json b/docs.json index a73afa8..ef13278 100644 --- a/docs.json +++ b/docs.json @@ -168,7 +168,9 @@ "api-reference/endpoints/users/get-a-users-points", "api-reference/endpoints/users/get-a-users-points-summary", "api-reference/endpoints/users/get-a-users-leaderboard", - "api-reference/endpoints/users/get-a-users-wrapped" + "api-reference/endpoints/users/get-a-users-wrapped", + "api-reference/endpoints/users/get-user-preferences", + "api-reference/endpoints/users/update-user-preferences" ] } ] diff --git a/platform/emails.mdx b/platform/emails.mdx index 9b9faae..4543f25 100644 --- a/platform/emails.mdx +++ b/platform/emails.mdx @@ -35,6 +35,13 @@ All emails are optional, but all four can be used simultaneously and can be cont To start sending emails with Trophy, you'll need to verify your domain and enable email triggers. + + Users can control which email notifications they receive through Trophy's + [user preferences API](/platform/users#notification-preferences). This allows + you to build a preference center in your application where users can opt in or + out of specific email types. + + ### Domain Verification Trophy supports sending emails from your own domain out-of-the-box. There are two ways to set this up, Single Sender Verification and DNS Verification. @@ -812,7 +819,14 @@ All emails that Trophy sends include an unsubscribe link and message. This is im wish to receive these emails, you can unsubscribe._ -Any recipient that clicks this link will no longer receive any emails from Trophy. +Any recipient that clicks this link will be taken to a branded page that allows them to control which emails notifications they receive. + + + As an alternative to the unsubscribe link, you can also build a preference + center in your application using Trophy's [user preferences + API](/platform/users#notification-preferences). This gives users more granular + control over which types of emails they receive. + ## Email Analytics diff --git a/platform/push-notifications.mdx b/platform/push-notifications.mdx index fc3bada..b3aef48 100644 --- a/platform/push-notifications.mdx +++ b/platform/push-notifications.mdx @@ -105,6 +105,13 @@ To achieve this you must provide Trophy with a few key details from your Expo ac Follow the steps below to start sending push notifications using Trophy. + + Users can control which push notifications they receive through Trophy's [user + preferences API](/platform/users#notification-preferences). This allows you to + build a preference center in your application where users can opt in or out of + specific notification types. + + Trophy support sending push notifications via 3 channels, [Apple Push Notification Service (APNs)](#apple-push-notification-service-apns), [Firebase Cloud Messaging (FCM)](#firebase-cloud-messaging-fcm) or [Expo Push Service](#expo-push-service). @@ -173,6 +180,10 @@ Follow the steps below to start sending push notifications using Trophy. Once enabled, Trophy will start sending push notifications automatically. + + Users can control which push notification types they receive through Trophy's [user preferences API](/platform/users#notification-preferences). When a user has disabled a notification type in their preferences, Trophy will respect that setting and won't send those notifications to that user. + +