diff --git a/api-reference/endpoints/points/get-all-points-triggers.mdx b/api-reference/endpoints/points/get-all-points-triggers.mdx
deleted file mode 100644
index 6673a6b..0000000
--- a/api-reference/endpoints/points/get-all-points-triggers.mdx
+++ /dev/null
@@ -1,3 +0,0 @@
----
-openapi: get /points/triggers
----
diff --git a/api-reference/endpoints/points/get-points-summary.mdx b/api-reference/endpoints/points/get-points-summary.mdx
index 7ac2423..cca6764 100644
--- a/api-reference/endpoints/points/get-points-summary.mdx
+++ b/api-reference/endpoints/points/get-points-summary.mdx
@@ -1,3 +1,3 @@
---
-openapi: get /points/summary
+openapi: get /points/{key}/summary
---
diff --git a/api-reference/endpoints/points/get-points.mdx b/api-reference/endpoints/points/get-points.mdx
new file mode 100644
index 0000000..a0bf039
--- /dev/null
+++ b/api-reference/endpoints/points/get-points.mdx
@@ -0,0 +1,3 @@
+---
+openapi: get /points/{key}
+---
diff --git a/api-reference/endpoints/users/get-a-users-points-summary.mdx b/api-reference/endpoints/users/get-a-users-points-summary.mdx
index baaa426..cd6d192 100644
--- a/api-reference/endpoints/users/get-a-users-points-summary.mdx
+++ b/api-reference/endpoints/users/get-a-users-points-summary.mdx
@@ -1,3 +1,3 @@
---
-openapi: get /users/{id}/points/event-summary
+openapi: get /users/{id}/points/{key}/event-summary
---
diff --git a/api-reference/endpoints/users/get-a-users-points.mdx b/api-reference/endpoints/users/get-a-users-points.mdx
index 578d3b9..c2ffb81 100644
--- a/api-reference/endpoints/users/get-a-users-points.mdx
+++ b/api-reference/endpoints/users/get-a-users-points.mdx
@@ -1,3 +1,3 @@
---
-openapi: get /users/{id}/points
+openapi: get /users/{id}/points/{key}
---
diff --git a/api-reference/openapi.yml b/api-reference/openapi.yml
index de00a3d..1afaebe 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.4'
+ version: "1.0.4"
paths:
/achievements:
get:
@@ -20,14 +20,14 @@ paths:
const response = await trophy.achievements.all();
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:
@@ -68,18 +68,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: []
@@ -112,12 +112,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:
@@ -129,7 +129,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
@@ -141,31 +141,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: []
@@ -177,7 +177,7 @@ paths:
type: object
properties:
user:
- $ref: '#/components/schemas/UpsertedUser'
+ $ref: "#/components/schemas/UpsertedUser"
description: The user that completed the achievement.
required:
- user
@@ -231,12 +231,12 @@ paths:
type: string
example: words-written
responses:
- '201':
+ "201":
description: Created event
content:
application/json:
schema:
- $ref: '#/components/schemas/EventResponse'
+ $ref: "#/components/schemas/EventResponse"
examples:
Successful operation:
value:
@@ -251,14 +251,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
@@ -270,7 +270,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
@@ -278,24 +278,24 @@ paths:
metricName: words written
metricThreshold: 100
points: 10
- '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: []
@@ -307,7 +307,7 @@ paths:
type: object
properties:
user:
- $ref: '#/components/schemas/UpsertedUser'
+ $ref: "#/components/schemas/UpsertedUser"
description: The user that triggered the event.
value:
type: number
@@ -333,7 +333,7 @@ paths:
user:
email: user@example.com
tz: Europe/London
- id: '18'
+ id: "18"
attributes:
department: engineering
role: developer
@@ -375,15 +375,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:
@@ -391,29 +391,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}:
get:
description: Get a single user.
@@ -442,12 +442,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:
@@ -455,29 +455,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
@@ -516,7 +516,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdatedUser'
+ $ref: "#/components/schemas/UpdatedUser"
description: The user object.
example:
email: user@example.com
@@ -525,12 +525,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:
@@ -538,26 +538,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
@@ -596,7 +596,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/UpdatedUser'
+ $ref: "#/components/schemas/UpdatedUser"
description: The user object.
example:
id: user-id
@@ -606,12 +606,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:
@@ -619,32 +619,32 @@ 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}/metrics:
get:
description: Get a single user's progress against all active metrics.
@@ -670,14 +670,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:
@@ -692,14 +692,14 @@ paths:
name: Novice Writer
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
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
@@ -707,24 +707,24 @@ paths:
metricId: d01dcbcb-d51e-4c12-b054-dc811dcdc623
metricValue: 2000
achievedAt: null
- '401':
- description: 'Unauthorized'
+ "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: []
@@ -760,12 +760,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:
@@ -780,13 +780,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
@@ -794,24 +794,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: []
@@ -868,7 +868,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.
@@ -876,9 +876,9 @@ paths:
schema:
type: string
format: date
- example: '2024-01-31'
+ example: "2024-01-31"
responses:
- '200':
+ "200":
description: Successful operation
content:
application/json:
@@ -891,7 +891,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
@@ -909,33 +909,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: []
@@ -982,17 +982,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/CompletedAchievementResponse'
+ $ref: "#/components/schemas/CompletedAchievementResponse"
examples:
Successful operation:
value:
@@ -1000,7 +1000,7 @@ paths:
trigger: api
key: completed-onboarding
name: Completed Onboarding
- achievedAt: '2021-01-01T00:00:00Z'
+ achievedAt: "2021-01-01T00:00:00Z"
badgeUrl: https://example.com/badge2.png
completions: 10
rarity: 90.13
@@ -1011,7 +1011,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: 8
rarity: 22.98
@@ -1020,28 +1020,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: 12
rarity: 89.52
- '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: []
@@ -1080,62 +1080,62 @@ 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"
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: []
@@ -1179,12 +1179,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:
@@ -1196,7 +1196,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
@@ -1204,24 +1204,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: []
@@ -1278,7 +1278,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.
@@ -1286,9 +1286,9 @@ paths:
schema:
type: string
format: date
- example: '2024-01-31'
+ example: "2024-01-31"
responses:
- '200':
+ "200":
description: Successful operation
content:
application/json:
@@ -1301,7 +1301,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
@@ -1319,33 +1319,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: []
@@ -1383,12 +1383,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:
@@ -1425,24 +1425,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: []
@@ -1471,12 +1471,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:
@@ -1500,15 +1500,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
@@ -1518,20 +1518,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: []
@@ -1560,7 +1560,7 @@ 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
@@ -1586,7 +1586,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:
@@ -1597,7 +1597,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:
@@ -1614,12 +1614,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.
@@ -1638,7 +1638,7 @@ components:
type:
type: string
description: The type of trigger
- enum: ['metric', 'achievement', 'streak']
+ enum: ["metric", "achievement", "streak"]
points:
type: number
description: The points awarded by this trigger.
@@ -1671,7 +1671,7 @@ components:
type: number
description: The user's total points after this award occurred.
trigger:
- $ref: '#/components/schemas/PointsTrigger'
+ $ref: "#/components/schemas/PointsTrigger"
GetUserPointsResponse:
title: GetUserPointsResponse
type: object
@@ -1695,7 +1695,7 @@ components:
type: array
description: Array of trigger awards that added points.
items:
- $ref: '#/components/schemas/PointsAward'
+ $ref: "#/components/schemas/PointsAward"
required:
- id
- name
@@ -1705,7 +1705,7 @@ components:
title: MetricEventPointsResponse
type: object
allOf:
- - $ref: '#/components/schemas/GetUserPointsResponse'
+ - $ref: "#/components/schemas/GetUserPointsResponse"
- type: object
properties:
added:
@@ -1724,7 +1724,7 @@ 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
@@ -1752,7 +1752,7 @@ components:
type: string
description: The name of the metric associated with this achievement (only applicable if trigger = 'metric')
currentStreak:
- $ref: '#/components/schemas/MetricEventStreakResponse'
+ $ref: "#/components/schemas/MetricEventStreakResponse"
description: >-
The user's current streak for the metric, if the metric has streaks
enabled.
@@ -1764,7 +1764,7 @@ components:
title: CompletedAchievementResponse
type: object
allOf:
- - $ref: '#/components/schemas/AchievementResponse'
+ - $ref: "#/components/schemas/AchievementResponse"
- type: object
properties:
achievedAt:
@@ -1775,7 +1775,7 @@ components:
title: AchievementWithStatsResponse
type: object
allOf:
- - $ref: '#/components/schemas/AchievementResponse'
+ - $ref: "#/components/schemas/AchievementResponse"
- type: object
properties:
completions:
@@ -1834,7 +1834,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
@@ -1844,7 +1844,7 @@ components:
achievements:
type: array
items:
- $ref: '#/components/schemas/CompletedAchievementResponse'
+ $ref: "#/components/schemas/CompletedAchievementResponse"
description: >-
A list of the metric's achievements and the user's progress towards
each.
@@ -1878,7 +1878,7 @@ components:
items:
type: string
description: The device token.
- example: ['token1', 'token2']
+ example: ["token1", "token2"]
subscribeToEmails:
type: boolean
default: true
@@ -1897,7 +1897,7 @@ components:
type: object
description: An object with editable user fields.
allOf:
- - $ref: '#/components/schemas/UpdatedUser'
+ - $ref: "#/components/schemas/UpdatedUser"
- type: object
properties:
id:
@@ -1911,7 +1911,7 @@ components:
type: object
description: A user of your application.
allOf:
- - $ref: '#/components/schemas/UpsertedUser'
+ - $ref: "#/components/schemas/UpsertedUser"
- type: object
properties:
control:
@@ -1922,12 +1922,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"
ErrorBody:
title: ErrorBody
type: object
@@ -1945,11 +1945,11 @@ components:
description: The unique ID of the completion.
example: 0040fe51-6bce-4b44-b0ad-bddc4e123534
achievement:
- $ref: '#/components/schemas/CompletedAchievementResponse'
+ $ref: "#/components/schemas/CompletedAchievementResponse"
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:
@@ -1975,17 +1975,17 @@ components:
achievements:
type: array
items:
- $ref: '#/components/schemas/CompletedAchievementResponse'
+ $ref: "#/components/schemas/CompletedAchievementResponse"
description: Achievements completed as a result of this event.
currentStreak:
- $ref: '#/components/schemas/MetricEventStreakResponse'
+ $ref: "#/components/schemas/MetricEventStreakResponse"
description: >-
The user's current streak for the metric, if the metric has streaks
enabled.
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 event.
required:
@@ -2014,7 +2014,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
@@ -2024,14 +2024,14 @@ components:
description: The unique ID of the trigger.
type:
type: string
- enum: ['metric', 'achievement', 'streak']
+ enum: ["metric", "achievement", "streak"]
description: The type of trigger.
points:
type: number
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
@@ -2111,7 +2111,7 @@ components:
type: array
description: Array of active triggers for this points system.
items:
- $ref: '#/components/schemas/PointsTriggerResponse'
+ $ref: "#/components/schemas/PointsTriggerResponse"
required:
- id
- name
diff --git a/assets/platform/achievements/check_user_completions.png b/assets/platform/achievements/check_user_completions.png
new file mode 100644
index 0000000..b8fc7ef
Binary files /dev/null and b/assets/platform/achievements/check_user_completions.png differ
diff --git a/assets/platform/emails/advanced_usage_singular_plural.png b/assets/platform/emails/advanced_usage_singular_plural.png
new file mode 100644
index 0000000..3eeddaf
Binary files /dev/null and b/assets/platform/emails/advanced_usage_singular_plural.png differ
diff --git a/assets/platform/emails/advanced_variables_prefix_suffix.png b/assets/platform/emails/advanced_variables_prefix_suffix.png
new file mode 100644
index 0000000..67fd5b5
Binary files /dev/null and b/assets/platform/emails/advanced_variables_prefix_suffix.png differ
diff --git a/assets/platform/emails/email_types.mp4 b/assets/platform/emails/email_types.mp4
new file mode 100644
index 0000000..d54a6c0
Binary files /dev/null and b/assets/platform/emails/email_types.mp4 differ
diff --git a/assets/platform/emails/email_types.png b/assets/platform/emails/email_types.png
deleted file mode 100644
index a9edfb7..0000000
Binary files a/assets/platform/emails/email_types.png and /dev/null differ
diff --git a/assets/platform/emails/email_variables_demo.mp4 b/assets/platform/emails/email_variables_demo.mp4
new file mode 100644
index 0000000..2848d67
Binary files /dev/null and b/assets/platform/emails/email_variables_demo.mp4 differ
diff --git a/assets/platform/emails/recap_trigger.png b/assets/platform/emails/recap_trigger.png
new file mode 100644
index 0000000..1c1c4cc
Binary files /dev/null and b/assets/platform/emails/recap_trigger.png differ
diff --git a/assets/platform/emails/streak_emails.png b/assets/platform/emails/streak_emails.png
new file mode 100644
index 0000000..31dddb0
Binary files /dev/null and b/assets/platform/emails/streak_emails.png differ
diff --git a/assets/platform/emails/streak_trigger.png b/assets/platform/emails/streak_trigger.png
new file mode 100644
index 0000000..8fda1c8
Binary files /dev/null and b/assets/platform/emails/streak_trigger.png differ
diff --git a/assets/platform/emails/using_variables.mp4 b/assets/platform/emails/using_variables.mp4
deleted file mode 100644
index 4a01c21..0000000
Binary files a/assets/platform/emails/using_variables.mp4 and /dev/null differ
diff --git a/assets/platform/events/create_custom_event_attribute.mp4 b/assets/platform/events/create_custom_event_attribute.mp4
new file mode 100644
index 0000000..11b115e
Binary files /dev/null and b/assets/platform/events/create_custom_event_attribute.mp4 differ
diff --git a/assets/platform/events/using_attributes_in_email_charts.mp4 b/assets/platform/events/using_attributes_in_email_charts.mp4
new file mode 100644
index 0000000..318c9d4
Binary files /dev/null and b/assets/platform/events/using_attributes_in_email_charts.mp4 differ
diff --git a/assets/platform/events/using_attributes_in_emails.mp4 b/assets/platform/events/using_attributes_in_emails.mp4
new file mode 100644
index 0000000..fe867af
Binary files /dev/null and b/assets/platform/events/using_attributes_in_emails.mp4 differ
diff --git a/assets/platform/points/create_system.mp4 b/assets/platform/points/create_system.mp4
new file mode 100644
index 0000000..f517fb5
Binary files /dev/null and b/assets/platform/points/create_system.mp4 differ
diff --git a/assets/platform/points/create_trigger.mp4 b/assets/platform/points/create_trigger.mp4
index 9385ff9..503f577 100644
Binary files a/assets/platform/points/create_trigger.mp4 and b/assets/platform/points/create_trigger.mp4 differ
diff --git a/assets/platform/points/points_analytics.png b/assets/platform/points/points_analytics.png
index c53d021..4793124 100644
Binary files a/assets/platform/points/points_analytics.png and b/assets/platform/points/points_analytics.png differ
diff --git a/assets/platform/users/create_custom_user_attribute.mp4 b/assets/platform/users/create_custom_user_attribute.mp4
new file mode 100644
index 0000000..b5f5479
Binary files /dev/null and b/assets/platform/users/create_custom_user_attribute.mp4 differ
diff --git a/assets/platform/users/segmenting_analytics.mp4 b/assets/platform/users/segmenting_analytics.mp4
new file mode 100644
index 0000000..5812de1
Binary files /dev/null and b/assets/platform/users/segmenting_analytics.mp4 differ
diff --git a/docs.json b/docs.json
index ff95606..03d549c 100644
--- a/docs.json
+++ b/docs.json
@@ -132,8 +132,8 @@
{
"group": "Points",
"pages": [
- "api-reference/endpoints/points/get-points-summary",
- "api-reference/endpoints/points/get-all-points-triggers"
+ "api-reference/endpoints/points/get-points",
+ "api-reference/endpoints/points/get-points-summary"
]
},
{
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..6ab6825
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+ "name": "docs",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {}
+}
diff --git a/platform/achievements.mdx b/platform/achievements.mdx
index 503ea97..9830daa 100644
--- a/platform/achievements.mdx
+++ b/platform/achievements.mdx
@@ -1,7 +1,7 @@
---
title: Achievements
description: Learn how to use Achievements in a gamified product experience with Trophy.
-"og:description": Use metric, standalone and streak achievements to rewards users for continued progress and to encourage them to discover new parts of your app.
+"og:description": Use metric, API and streak achievements to rewards users for continued progress and to encourage them to discover new parts of your app.
icon: trophy
---
@@ -39,7 +39,7 @@ Watch Charlie run walk through using achievements in a NextJS application:
## Achievement Types
-Trophy offers three types of achievements, [Metric](#metric-achievements), [Standalone](#standalone-achievements) and [Streak achievements](#streak-achievements), detailed below.
+Trophy offers three types of achievements, [Metric](#metric-achievements), [API](#api-achievements) and [Streak achievements](#streak-achievements), detailed below.
### Metric Achievements
@@ -62,9 +62,9 @@ When achievements are unlocked, Trophy includes information about the unlocked a
-### Standalone Achievements
+### API Achievements
-Standalone achievements can only be completed once and are useful for rewarding users for taking specific actions.
+API achievements can only be completed once and are useful for rewarding users for taking specific actions.
Common examples include:
@@ -72,9 +72,9 @@ Common examples include:
- A user linking their social account to a platform
- A user sharing their product experience on social media
-Standalone achievements serve as an easy way to reward users for completing any action that you think is important for retention.
+API achievements serve as an easy way to reward users for completing any action that you think is important for retention.
-Just like metric achievements, standalone achievements can also trigger automated [Achievement Emails](/platform/emails#achievement-emails) if configured.
+Just like metric achievements, API achievements can also trigger automated [Achievement Emails](/platform/emails#achievement-emails) if configured.
### Streak Achievements
@@ -82,7 +82,7 @@ Streak achievements are directly tied to a user's [Streak](/platform/streaks) an
You can create as many streak achievements as you like for increasing lengths of streak, for example 7 days, 30 days and 365 days to motivate users to use your app more and more.
-Just like metric and standalone achievements, you can add a custom name and assign a badge to streak achievements.
+Just like metric and API achievements, you can add a custom name and assign a badge to streak achievements.
## Creating Achievements
@@ -104,14 +104,26 @@ To create new achievements, head to the [achievements page](https://app.trophy.s
Enter a name for the achievement. This will be returned from APIs and made available for use in emails and other areas of Trophy where appropriate.
+
+ Enter a short description of the achievement. This will be returned from APIs
+ and made available for use in emails and other areas of Trophy where
+ appropriate.
+
+
+
+ You can upload and assign a badge to the achievement that will be returned in
+ API responses and made available in emails and other areas of Trophy where
+ appropriate.
+
+
Choose how you want this achievement to be unlocked.
-- Choosing **Metric** will mean the achievement will be automatically unlocked when the user's total reaches the achievement trigger value.
+- Choosing **Metric** will mean the achievement will be automatically unlocked when the user's metric total reaches the achievement trigger value.
- Choosing **Streak** will mean the achievement will be automatically unlocked when the user's streak length reaches the achievement trigger value.
-- Choosing **API Call** will mean the achievement will only be unlocked when explicitly marked as completed by your code through an API call.
+- Choosing **API Call** will mean the achievement will only be unlocked when explicitly marked as completed by your code through a request to the [complete achievement API](/api-reference/endpoints/achievements/mark-an-achievement-as-completed).
@@ -126,10 +138,13 @@ To create new achievements, head to the [achievements page](https://app.trophy.s
-
- You can upload and assign a badge to the achievement that will be returned in
- API responses and made available in emails and other areas of Trophy where
- appropriate.
+
+ You can assign _attribute filters_ to an achievement to further restrict who can unlock them and when.
+
+- To limit a **Metric** achievement to only apply to events with specific [custom event attributes](/platform/events#custom-event-attributes), select an attribute and enter a value in the **Event Attribute** section.
+
+- To limit any type of achievement to only apply to a user with one or more specific [custom user attributes](/platform/users#custom-user-attributes), add attributes and the desired values in the **User Attributes** section.
+
@@ -137,13 +152,77 @@ To create new achievements, head to the [achievements page](https://app.trophy.s
+## Managing Achievements
+
+Trophy has built in tools to help you test and control which achievements can be unlocked, by who and when, without affecting production.
+
+### Achievement Statuses
+
+Here's an overview of the different achievement statuses and what they mean.
+
+**Inactive**
+
+All achievements are created as inactive. Inactive achievements can't be completed and aren't returned in any achievement APIs. Users won't see them until you make them active.
+
+**Active**
+
+When you make an achievement active, it makes it 'live'. Users can complete it and it will be returned from all achievement APIs.
+
+**Locked**
+
+When you lock an achievement, users who haven't unlocked it yet won't be able to unlock it anymore, but users who have already unlocked it won't be affected.
+
+Locked acheivements are only returned in APIs for users who have already achieved them.
+
+**Archived**
+
+Archvied achievements can't be completed and aren't returned in any achievement APIs.
+
+
+ Once you archive an achievement it disapears from Trophy so be sure to only
+ archive achievements that you no longer need.
+
+
+Archived achievements can be restored by [contacting support](#get-support).
+
+### Acheivement Workflow
+
+Achievements can be moved through different statuses according to the following workfow:
+
+```mermaid
+flowchart LR
+ A@{ shape: rounded, label: "Inactive" }
+ B@{ shape: rounded, label: "Active" }
+ C@{ shape: rounded, label: "Active" }
+ D@{ shape: rounded, label: "Locked" }
+ E@{ shape: rounded, label: "Archived" }
+ F@{ shape: rounded, label: "Locked" }
+ G@{ shape: rounded, label: "Active" }
+ H@{ shape: rounded, label: "Archived" }
+ A-->B
+ C-->D
+ D-->E
+ C-->E
+ F-->G
+ F-->H
+ style A fill:#FDFDEA,stroke:#F7F0D5
+ style B fill:#F2FAF7,stroke:#E2F6E6
+ style C fill:#F2FAF7,stroke:#E2F6E6
+ style D fill:#eee,stroke:#ddd
+ style E fill:#ddd,stroke:#ccc
+ style F fill:#eee,stroke:#ddd
+ style G fill:#F2FAF7,stroke:#E2F6E6
+ style H fill:#ddd,stroke:#ccc
+
+```
+
## Completing Achievements
If you're using metric achievements, there's no need to explicitly _complete_ achievements. Once you've set up [metric tracking](/platform/events#tracking-metric-events) in your code, all achievements linked to the metric will be automatically tracked.
Similarly, if you're using streak achievements, all achievements related to the user's streak will automatically be unlocked when a user reaches the respective streak length.
-However if you're using any standalone achievements, you will have to mark them as completed for each user as appropriate. To do this, you can use the [Complete Achievement API](/api-reference/endpoints/achievements/mark-an-achievement-as-completed) using the `key` of the achievement you want to complete.
+However if you're using any API achievements, you will have to mark them as completed for each user as appropriate. To do this, you can use the [Complete Achievement API](/api-reference/endpoints/achievements/mark-an-achievement-as-completed) using the `key` of the achievement you want to complete.
This will return back a response that contains details of the achievement that was completed that can be used in any post-completion workflows, like showing an in-app notification.
@@ -162,6 +241,28 @@ This will return back a response that contains details of the achievement that w
}
```
+## Backdating Achievements
+
+By default, whenever you move an achievement to 'Active' [status](#managing-achievements), Trophy will check if any existing users meet the requirements of the achievment and complete it for them behind the scenes.
+
+This means when you release new achievments into production, or edit an existing live achievement, backdating will happen automatically.
+
+
+ When achievements are completed in this way, users don't receive any
+ notifications this has happened. This is to prevent changes to your
+ achievements in Trophy resulting in users getting lots of notifications.
+
+
+You can check how many users have completed achievements at any time on the [acheivements page](https://app.trophy.so/achievements) in the Trophy dashboard. The _Users_ column in the acheivements can update during backdating.
+
+
+
+
+
## Using Badges
@@ -216,15 +317,18 @@ To display a high-level overview of all achievements users can complete, use the
>
-The all achievements endpoint returns a list of all achievements within your Trophy account along with details of 'rarity' (the percentage of users who have completed each achievement) as follows:
+The all achievements endpoint returns a list of all achievements within your Trophy account. Each achievement returned also includes `completions` (the number of users who have compelted the acheivement) and `rarity` (the percentage of users who have completed the achievement) as follows:
### User Achievements
-If instead you're building user-specific UI elements, then use the [user achievements endpoint](/api-reference/endpoints/users/get-a-users-completed-achievements) to get only the achievements a specific user has completed.
+If instead you're building user-specific UI elements, then use the [user achievements endpoint](/api-reference/endpoints/users/get-a-users-completed-achievements) to return achievements a specific user has completed.
-Use this data to display achievements against a user's profile for example.
+
+ You can also include achievements that a user has yet to complete by including
+ the query parameter `includeIncomplete=true`.
+
diff --git a/platform/emails.mdx b/platform/emails.mdx
index 3084fc8..1e2f442 100644
--- a/platform/emails.mdx
+++ b/platform/emails.mdx
@@ -14,22 +14,216 @@ Trophy supports 4 types of emails, each of which is designed to suit a common sc
All emails are optional, but all four can be used simultaneously and can be controlled from the [Emails](https://app.trophy.so/emails/configure) page in the Trophy dashboard.
-
+
-### Achievement Emails
+- **Achievement emails** are sent to users each time they unlock an [Achievement](/platform/achievements).
+- **Recap emails** are sent to users on a pre-defined frequency to summarize progress. Recap Emails can be configured to be sent daily, weekly, monthly or yearly depending on your use case.
+- **Reactivation emails** are sent to users after they become inactive with the goal of bringing them back to your app.
+- **Streak emails** are automatically sent to users reminding them to extend their [Streak](/platform/streaks).
+
+## Sending Emails
+
+To start sending emails with Trophy, you'll need to verify your domain and enable email triggers.
+
+### 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.
+
+All domain settings can be found in the [Domains](https://app.trophy.so/emails/domains) page in the Trophy dashboard.
+
+
+ If you're looking to get set up quickly we recommend starting with Single
+ Sender Verification then setting up DNS Verification when you're ready to move
+ to production.
+
+
+
+
+ Quickly verify a single email address
+
+
+ Recommended for production use
+
+
+
+#### Sender Verification (Basic)
+
+During onboarding you'll be prompted to set up Sender Verification. This is a super simple way to quickly verify a single email address that you want to use with Trophy without needing to change any code or DNS settings.
+
+You'll be prompted to enter the email address, from name and reply-to email that you'd like Trophy to use when sending emails:
+
+
+
+
+
+Trophy will send a verification email to that address. Simply click the link in the email to let Trophy know what you own the address and you'll be good to go.
+
+
+ The email you receive will come from our email provider, Postmark. So keep an
+ eye out for 'Postmark Support' in your inbox!
+
+
+Sender Verification is great for getting started but is limited in that you won't benefit from your existing email reputation and can only send emails from one address.
+
+Also, if you want to change the address in the future, you'll have to go through Sender Verification again which you can do in the [settings screen](https://app.trophy.so/integration?tab=domains).
+
+#### DNS Verification (Advanced)
+
+Recommended for production use
+
+For production use we recommend DNS Verification. Once set up, this allows you to configure Trophy to send emails from any address on your domain. So if you want to change the address in future, you won't need to verify again.
+
+Completing DNS verification also gives you the full benefits of any existing domain reputation and is the best way to make sure your emails avoid the spam folder.
+
+This does however require adding a couple of new entries into your DNS to allow Trophy to verify you own the domain.
+
+Follow the steps below to set up DNS verification:
+
+
+
+ Within the Emails page, you'll find the [Domains](https://app.trophy.so/emails/domains) tab which is where you'll configure everything related to the email domain Trophy will use to send emails on your behalf.
+
+
+
+ Head down to the DNS Verification section and enter the domain you want to set up with Trophy.
+
+ You can also also configure a custom Return Path. This is where Trophy will forward notifications of bounced emails to help you investigate deliverability issues:
+
+
+
+
+
+
+
+
+
+ Once you've entered your email domain, Trophy will provide you with details for two new DNS records that you'll need to add to your DNS provider.
+
+
+
+
+
+ - First is the **DKIM** record which is used by inbox providers like Google to verify the authenticity of emails. Enter the name and value provided as a new **TXT** record in your DNS provider.
+ - Second is the **Return Path** record. This is used to forward notifications of email bounces to your domain. Enter the name and value provided as a new **CNAME** record in your DNS provider.
+
+ Here are the pages for the most common DNS providers on how to set up new records:
+
+
+
+ [Add a TXT record](https://www.godaddy.com/en-uk/help/add-a-txt-record-19232)
+ [Add a CNAME record](https://www.godaddy.com/en-uk/help/add-a-cname-record-19236)
+
+
+ [Add DNS records](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records)
+
+
+ [Add a CNAME record](https://www.namecheap.com/support/knowledgebase/article.aspx/9646/2237/how-to-create-a-cname-record-for-your-domain/)
+ [Add a TXT record](https://www.namecheap.com/support/knowledgebase/article.aspx/317/2237how-do-i-add-txtspfdkimdmarc-records-for-my-domain/#:~:text=this%20guide%20.-,DKIM%20records,-DKIM%20(DomainKeys%20Identified))
+
+
+
+ Note: If you're using a proxy like Cloudflare, make sure to turn it off for these records or Trophy won't be able to properly verify them.
+
+
+
+
+
+ Once you've added the two records into your DNS settings, hit the refresh icon and Trophy will attempt to verify the records for you.
+
+ Usually Trophy can verify records within a few minutes but bear in mind that DNS changes can take up to a few hours to fully propogate.
+
+ If you see the following alert, the records may not have propogated yet, or there may be an issue with your setup.
+
+
+
+
+
+ Once you're sure everything's set up correctly in your DNS provider, hit refresh and Trophy will attempt to verify your DNS records once again.
-Achievement emails are sent to users each time they unlock an [Achievement](/platform/achievements).
+ As soon as you see the following message, you know everything's verified:
-### Recap Emails
+
+
+
-Recap emails are sent to users on a pre-defined frequency to summarize progress. Recap Emails can be configured to be sent daily, weekly, monthly or yearly depending on your use case.
+
-### Reactivation Emails
+
-As Trophy monitors usage across your entire userbase, it can detect when users become inactive and send automated win-back emails to encourage them to return.
+ Once your DNS records are verified, it's time to choose the email address you want to send emails from. Note that now you've fully verified your domain, you can change this address whenever you like without impacting deliverability.
-Emails are sent as follows:
+ Simply enter the email address you want Trophy to send from, the name to show to users in the inbox when they receive emails and a support email address they can use to contact you if needed:
+
+
+
+
+
+
+
+
+
+### Email Triggers
+
+You can manage email triggers on the [Email Configuration](https://app.trophy.so/emails/configure) page of the Trophy dashboard. There, you'll see a list of triggers that can be turned on or off:
+
+#### Recap Emails
+
+The **Recap** trigger sends daily, weekly, or monthly progress reports to users. You can change the frequency of these emails on the [Integration](https://app.trophy.so/integration) page using the **Aggregation Period** setting.
+
+
+
+
+
+#### Reactivation Emails
+
+The **Reactivation** trigger sends win-back emails to users after they become inactive. These emails are sent according to the following timeline:
- After 3 days of inactivity
- After 5 days of inactivity
@@ -37,9 +231,80 @@ Emails are sent as follows:
- After 14 days of inactivity
- After 30 days of inactivity
-### Streak Reminder Emails
+
+
+
+
+#### Streak Emails
+
+The **Streak** trigger sends an email to each user before their streak expires. These emails are sent according to the streak frequency you configured on the [Streaks page](https://app.trophy.so/streaks):
+
+- If your app uses a **daily streak**, this email will send four hours before the end of the day (in each user's timezone).
+- For **weekly streaks**, it will send on Friday morning.
+- For **monthly streaks**, it will send on the 25th of the month.
+
+
+
+
+
+#### Achievement Emails
+
+The **Achievement** trigger sends an email congratulating users when they complete an [achievements](/platform/achievements) you've configured in Trophy. These emails send between 5-9PM on the day the achievement is completed, or the next day at 5PM if it is past 9PM when the user completes the achievement.
+
+
+
+
+
+#### Email Templates
-Streak reminder emails are automatically sent to users up to 4 hours before they are about to lose their [Streak](/platform/streaks).
+For each trigger, you can assign an **Email Template** that the trigger uses. You can leave this set to _Trophy Default_ or [design your own email templates](#designing-emails) right in the Trophy dashboard.
+
+
+
+
+
+
+ For **Achievement Emails**, you can configure a different template for each
+ type of achievement. For example, you could have a different template for API
+ achievements, streak achievements, and each metric with metric achievements.
+
+
+#### Limiting Emails to Specific Types of Users
+
+Each email trigger can be limited to users with specific [custom user attribute](/platform/users#custom-user-attributes) values. For each attribute you'd like to restrict the email to, click the Plus icon next to the **User Filters** header for the email trigger, then select the attribute and enter the desired value. Only users that have **all** specified attribute values will receive emails from this trigger.
+
+
+
+
+
+#### Time Zones
+
+If you specify a timezone for each user through [User Identification](/platform/users#param-tz), Trophy will use that local time zone to schedule emails according to the logic specified above. If you do not provide time zones for the users you identify, Trophy will default to Eastern Time.
## Designing Emails
@@ -273,21 +538,13 @@ Where achievements have badges, these will be automatically shown, as well as th
### Email Variables
-Trophy provides an expansive set of dynamic variables that are useful for designing highly relevant and personalized emails. Variables bring context from your Trophy account, the recipient's progress data, and email specific settings to your email templates.
+Trophy provides an expansive set of email variables that can be used to insert highly relevant and personalized copy into the body of emails and subject lines.
-
-
-
+Variables bring context from your Trophy account, the recipient's progress data, and email specific settings to your email templates.
+
+Email variables can be inserted by typing `@` in any block that supports rich text, like headers, paragraphs, and buttons, and searching for your chosen variable.
-Email variables can be inserted by typing `{{` in any block that supports rich text, like headers, paragraphs, and buttons, and searching for your chosen variable. The editor will insert the variable code for you.
+This will open up the variable editor window where you can configure variables as in the demo below.
You can also use variables in email subject lines.
@@ -298,108 +555,132 @@ Email variables can be inserted by typing `{{` in any block that supports rich t
loop
playsInline
className="w-full aspect-video"
- src="../assets/platform/emails/using_variables.mp4"
+ src="../assets/platform/emails/email_variables_demo.mp4"
>
-See below for a full list of all email variables supported by the email builder:
-
-
- Variables related to the recipient of the email.
-
-
-
- The full name of the user, if set.
-
-
-
-
-
- Variables referencing data from metrics within your Trophy account.
-
- In all metric variables, `key` relates to the unique reference you set for the metric when created. You can find this in the details page for each metric.
-
-
- Variables for a metric called 'Words written' with a `key` of `words` would be accessed with a `metrics.words` prefix. For example `metrics.words.percentile`.
-
-
-
-
- Indicates where the recipient's all time metric total ranks compared to all other tracked users. For example, if a user is in the 90th percentile, their all time metric total is higher than 90% of users that have at least one event recorded against the metric.
-
-
- The recipent's percentile within the most recent [Aggregation Period](#aggregation-period).
-
-
- The recipient's current total value of all events recorded against the metric.
-
-
- The percentage increase (or decrease) in the recipient's metric total as compared to the last [Aggregation Period](#aggregation-period). For example if the recipent has doubled their metric total within the aggregation period, `percentChange` would show +100. We leave it up to you to display a '%' sign if required.
-
-
- The absolute increase (or decrease) in the recipient's metric total as compared to the last [Aggregation Period](#aggregation-period). For example if the recipents metric total has increased from 500 to 750, `changeThisPeriod` would show 250.
-
-
-
-
-
- Variables related to the recipient's streak.
+See below for a full list of all email variables supported by the email builder, broken down by category.
+
+
+
+Variables related to the recipient of the email.
+
+- **Name**: The recipient's name, if set
+
+Additionally all [custom user attributes](/platform/users#custom-user-attributes) are available as email variables.
-
-
- `true` if the recipient has an active streak, `false` otherwise.
-
-
- `true` if the recipient has extended their streak within the current streak period, `false` otherwise.
-
-
- The number of consequtive periods that the user has kept their streak. 0 if the user does not have an active streak.
-
-
- The number of days since the user last extended their streak. 0 if the user has an active streak.
-
-
-
-
-
- Variables related to the current setting of the data [Aggregation Period](#aggregation-period).
-
-
-
- The string representation of the current aggregation period. For example 'June 1 - June 7'.
-
-
-
-
-
+
+
+ Variables related to the recipients tracked event data againt metrics.
+
+Each Trophy metric supports the following email variables:
+
+- **Metric Name**: The name of the metric
+- **Metric Units**: The metric's units
+- **Current Total**: The sum of all the recipients event values to date
+- **Change This Period**: Absolute change in the recipients current total in the current aggregation period
+- **Change This Period (%)**: Percent change in the recipients current total in the current aggregation period
+- **Percentile (All Time)**: The recipients current total compared to all other users for all time
+- **Percentile (This Period)**: The recipients current total compared to all other users in the current aggregion period
+
+Additionally, the **Highest** and **Lowest** dynamic aliases support the same set of variables. When using these aliases, Trophy will pick the metric where the recipient has either the highest or lowest current total at send time.
+
+When using metric variables, you also have the option of filtering the data that any of the above variables reference through a [custom event attribute](/platform/events#custom-event-attributes).
+
+
+
+
+
+Similarly to metrics, each points system has the following variables that can be used to add dynamic data to email copy:
+
+- **Current Total**: The recipients total points
+- **Change This Period**: Absolute change in the recipients total points in the current aggregation period
+- **Change This Period (%)**: Percent change in the recipients total points in the current aggregation period
+- **Percentile (All Time)**: The recipients total points compared to all other users for all time
+- **Percentile (This Period)**: The recipients total points compared to all other users in the current aggregion period
+
+.
+
+
+
- Only relevant in the context of [Achievement Emails](#achievement-emails).
+ These variables are only relevant for [achievement emails](#achievement-emails).
-
-
- The `name` of the unlocked achievement that triggered the email.
-
-
- `true` if the achievement the recipent unlocked is the last achievement for it's metric, `false` otherwise.
-
-
- The percentage progress that the recipent has made to the next achievement against the same metric. 100 if `isLastAchievement` is true.
-
-
-
-
-
+When configuring a template for use with achievement emails, the following variables are available:
+
+- **Is Final Achievement**: If the achievement triggering the email is part of a series of metric achievements, this is true when the achievment is the final achievement in the series
+- **Percent To Next Achievement**: If the achievement triggering the email is part of a series of metric achievements, this is the percentage until the user unlocks the next achievment in the series
+- **Achievement Name**: The name of the achievement that triggered the email
+- **Achievement Description**: The description of the achievement that triggered the email
+
+.
+
+
+
+ Variables related to the recipient's streak.
+
+- **Has Active Streak**: True if the recipient has an active streak at the time the email is sent, false otherwise
+- **Streak Length**: The length of the recipient's current streak
+- **Streak Extended**: True if the recipient's streak was extended, false otherwise
+- **Days Since Last Extended**: The number of days since the user last extended their streak
+
+.
+
+
+
- Only relevant in the context of [Reactivation Emails](#reactivation-emails).
+ These variables are only relevant for [reactivation emails](#reactivation-emails).
+
+
+- **Message Number**: The number of the message in the reactivation sequence (1-5)
+
+.
+
+
+
+
+ These variables are only relevant for [recap emails](#recap-emails).
-
-
- Trophy sends 5 reactivation emails over 30 days. This is the number of the current email in the sequence. Useful for displaying different email content throughout the sequence.
-
-
-
+- **Current Period Date Range**: The start and end dates of the current aggregation period
+
+.
+
+
+
+
+#### Advanced Usage
+
+There are a couple of additional options to consider when using emails variables.
+
+**Prefix & Suffix**
+
+You can provide a prefix and suffix for text variables like the recipients name, or the name of a particular metric.
+
+
+
+
+
+If the value of the variable fails to render when the email is sent, then Trophy won't display the variable or the prefix or suffix to keep emails clean.
+
+**Singular & Plural**
+
+When using numeric variables like the recipients current points total or metric total, you can also provide a singular and plural suffix to accompany it.
+
+
+
+
### Text Variations
@@ -501,54 +782,6 @@ The email editor offers rich text formatting including bold, italics, [hyperlink
>
-It also supports more complex text formatting use cases based on the [Mustache](https://mustache.github.io/mustache.5.html) specification with the most common use case being to conditionally show text based on the value of [Email Variables](#email-variables).
-
-
- If you need more complex conditional formatting, or aren't familiar with
- Mustache, consider using [Conditional Blocks](#conditional-blocks) instead.
-
-
-Here's an example where we show text if the email recipient has an active streak or not:
-
-```
-{{#streak.active}}
- You're on a streak!
-{{/streak.active}}
-```
-
-Additionally, the editor support pluralization. In the below example we show different text based on if the value of the `metrics.words.currentTotal` is `1` (singular) or greater than `1` (plural).
-
-```
-{{#plural}}
- {{metrics.words.currentTotal}} words written
-{{/plural}}
-{{#singular}}
- {{metrics.words.currentTotal}} word written
-{{/singular}}
-```
-
-
- For `#plural` and `#singular` to work, the first entry must be a number
- variable.
-
-
-## Email Customization
-
-### Aggregation Period
-
-
-
-
-
-The aggregation period controls the timeframe over which blocks like the [Progress Chart](#progress-chart) display usage. It also controls the frequency at which [Recap Emails](#recap-emails) are sent. Possible values are daily, weekly, monthly or yearly.
-
-Head into the [Integration](https://app.trophy.so/integration) page to manage this setting.
-
### Font Style
On the [email configure page](https://app.trophy.so/emails/configure), you'll find a setting to change the font style used in all emails.
@@ -564,183 +797,6 @@ On the [email configure page](https://app.trophy.so/emails/configure), you'll fi
Other email styles are pulled from your Trophy account's [Branding](https://app.trophy.so/branding) settings.
-## Send-time Optimization
-
-In most cases, emails sent by Trophy are sent at **17:00PM ET**, however sending emails to users based on their local timezone usually results in better engagement rates.
-
-That's why if through [User Identification](/platform/users#param-tz) you specify a timezone for each user, Trophy will optimize the send-time for you by sending emails to users at 17:00PM in their local timezone.
-
-## Setting up Emails
-
-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.
-
-All domain settings can be found in the [Domains](https://app.trophy.so/emails/domains) page in the Trophy dashboard.
-
-
- If you're looking to get set up quickly we recommend starting with Single
- Sender Verification then setting up DNS Verification when you're ready to move
- to production.
-
-
-
-
- Quickly verify a single email address
-
-
- Recommended for production use
-
-
-
-### Sender Verification (Basic)
-
-During onboarding you'll be prompted to set up Sender Verification. This is a super simple way to quickly verify a single email address that you want to use with Trophy without needing to change any code or DNS settings.
-
-You'll be prompted to enter the email address, from name and reply-to email that you'd like Trophy to use when sending emails:
-
-
-
-
-
-Trophy will send a verification email to that address. Simply click the link in the email to let Trophy know what you own the address and you'll be good to go.
-
-
- The email you receive will come from our email provider, Postmark. So keep an
- eye out for 'Postmark Support' in your inbox!
-
-
-Sender Verification is great for getting started but is limited in that you won't benefit from your existing email reputation and can only send emails from one address.
-
-Also, if you want to change the address in the future, you'll have to go through Sender Verification again which you can do in the [settings screen](https://app.trophy.so/integration?tab=domains).
-
-### DNS Verification (Advanced)
-
-Recommended for production use
-
-For production use we recommend DNS Verification. Once set up, this allows you to configure Trophy to send emails from any address on your domain. So if you want to change the address in future, you won't need to verify again.
-
-Completing DNS verification also gives you the full benefits of any existing domain reputation and is the best way to make sure your emails avoid the spam folder.
-
-This does however require adding a couple of new entries into your DNS to allow Trophy to verify you own the domain.
-
-Follow the steps below to set up DNS verification:
-
-
-
- Within the Emails page, you'll find the [Domains](https://app.trophy.so/emails/domains) tab which is where you'll configure everything related to the email domain Trophy will use to send emails on your behalf.
-
-
-
- Head down to the DNS Verification section and enter the domain you want to set up with Trophy.
-
- You can also also configure a custom Return Path. This is where Trophy will forward notifications of bounced emails to help you investigate deliverability issues:
-
-
-
-
-
-
-
-
-
- Once you've entered your email domain, Trophy will provide you with details for two new DNS records that you'll need to add to your DNS provider.
-
-
-
-
-
- - First is the **DKIM** record which is used by inbox providers like Google to verify the authenticity of emails. Enter the name and value provided as a new **TXT** record in your DNS provider.
- - Second is the **Return Path** record. This is used to forward notifications of email bounces to your domain. Enter the name and value provided as a new **CNAME** record in your DNS provider.
-
- Here are the pages for the most common DNS providers on how to set up new records:
-
-
-
- [Add a TXT record](https://www.godaddy.com/en-uk/help/add-a-txt-record-19232)
- [Add a CNAME record](https://www.godaddy.com/en-uk/help/add-a-cname-record-19236)
-
-
- [Add DNS records](https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-dns-records/#create-dns-records)
-
-
- [Add a CNAME record](https://www.namecheap.com/support/knowledgebase/article.aspx/9646/2237/how-to-create-a-cname-record-for-your-domain/)
- [Add a TXT record](https://www.namecheap.com/support/knowledgebase/article.aspx/317/2237how-do-i-add-txtspfdkimdmarc-records-for-my-domain/#:~:text=this%20guide%20.-,DKIM%20records,-DKIM%20(DomainKeys%20Identified))
-
-
-
- Note: If you're using a proxy like Cloudflare, make sure to turn it off for these records or Trophy won't be able to properly verify them.
-
-
-
-
-
- Once you've added the two records into your DNS settings, hit the refresh icon and Trophy will attempt to verify the records for you.
-
- Usually Trophy can verify records within a few minutes but bear in mind that DNS changes can take up to a few hours to fully propogate.
-
- If you see the following alert, the records may not have propogated yet, or there may be an issue with your setup.
-
-
-
-
-
- Once you're sure everything's set up correctly in your DNS provider, hit refresh and Trophy will attempt to verify your DNS records once again.
-
- As soon as you see the following message, you know everything's verified:
-
-
-
-
-
-
-
-
-
- Once your DNS records are verified, it's time to choose the email address you want to send emails from. Note that now you've fully verified your domain, you can change this address whenever you like without impacting deliverability.
-
- Simply enter the email address you want Trophy to send from, the name to show to users in the inbox when they receive emails and a support email address they can use to contact you if needed:
-
-
-
-
-
-
-
-
-
## Handling Unsubscribes
All emails that Trophy sends include an unsubscribe link and message. This is important for maintaining compliance with regulations and it's not possible to hide it.
@@ -777,7 +833,7 @@ Trophy has built-in analytics for all Emails that it sends. This includes:
- Yes! Sending emails from your own domain is supported out-of-the-box. Follow the steps in the section on [Settings up Emails](#setting-up-emails) to get started.
+ Yes! Sending emails from your own domain is supported out-of-the-box. Follow the steps in the section on [sending emails](#sending-emails) to get started.
{" "}
diff --git a/platform/events.mdx b/platform/events.mdx
index cb3cf0d..27be52a 100644
--- a/platform/events.mdx
+++ b/platform/events.mdx
@@ -14,15 +14,134 @@ Events represent individual user interactions against [Metrics](/platform/metric
When you [integrate metrics](#tracking-metric-events) into your platform, you're setting up your platform to continuously stream events to your Trophy metrics for each user interaction. These interactions then drive all the gamification features you set up around these metrics.
-## Key attributes
+## Key Attributes
-### Metric-backed
+Events only have one required attribute, `value`. The value of an event is the numerical amount that will be added to the user's total metric count as a result of the user interaction it relates to.
-Each event increases or decreases the total value of a specific metric that you've configured in Trophy for a specific user.
+The value can be positive or negative, and can be a whole number or a decimal.
-### Value
+## Custom Event Attributes
-The value of an event is the numerical amount that will be added to the user's total metric count as a result of the user interaction it relates to. The value can be positive or negative, and can be a whole number or a decimal.
+You can specify a number of custom event attributes to help you track additional information relevant to your use case against events you send to Trophy.
+
+For example, a language learning app might have a 'Questions Completed' metric and use a custom event attribute to store wether the answer to each question was correct.
+
+Similarly a fitness app might use an 'Excercises Completed' metric and use a custom event attribute to store the weight that was used in each excercise and another custom event attribute to store how long the excercise lasted.
+
+Using custom event attributes in this way allows you to enrich events in Trophy with additional context relevant to your use case and use it to power even more engaging gamification features.
+
+### Creating Attibutes
+
+To create a new custom event attribute, head to the metrics page in the Trophy dashboard and hit the _Add Event Attribute_ button.
+
+Give the attribute a name and a unique key, you'll use the key when referencing the attribute in API calls.
+
+
+
+
+
+### Setting Attributes
+
+To set the value of a custom attribute on an event, pass its value in the `attributes` object in your metric tracking code.
+
+
+ Trophy will only set values of attributes that have first been created
+ in the dashboard. We do this to help you keep a clean set of attributes and
+ prevent accidental overwrites.
+
+If you receive an error similar to the following then you might have miss-spelled the attribute key in the request, or you need to create the attribute first in the Trophy dashboard:
+
+```json
+{
+ "error": "Invalid attribute keys: devce. Please ensure all attribute keys match those set up at https://app.trophy.so/metrics."
+}
+```
+
+
+
+Here's an example of an event payload where the values of two attributes, `device` and `duration`, are set:
+
+```json {7-10}
+{
+ "user": {
+ "id": "18",
+ "tz": "Europe/London"
+ },
+ "value": 25,
+ "attributes": {
+ "device": "ios",
+ "duration": "120"
+ }
+}
+```
+
+### Using Attributes
+
+Custom event attributes can be used to power more advanced triggers for achievements and points and can be used in email templates to customize copy and to control the data shown in charts.
+
+#### Advanced Feature Triggers
+
+Custom event attributes can be used to set up achievements or points triggers that only track events with specific attribute values. Follow the links to the relevant pages below to learn more.
+
+
+
+ Configure achievements that can only be unlocked by events with certain
+ attribute values.
+
+
+ Set up points triggers to only award points from events with specific
+ attribute values.
+
+
+
+#### Email Customization
+
+If you use any Trophy [Emails](/platform/emails), event attributes can be used to customize the data shown in certain email blocks.
+
+Firstly, when using metric-based variables in email copy you can use event attributes to further control what data the variable refrences.
+
+For example here's a case where we use an email variable to tell users what their total number of workouts they've done on different gym equipment is using a metric 'Workouts' and an attribute 'Equipment':
+
+
+
+
+
+Secondly, here's an example where we add a chart to an email that shows users how many workouts they've done on a bike over time:
+
+
+
+
+
+There's a huge number of possibilities here, so get creative!
## Tracking Metric Events
diff --git a/platform/points.mdx b/platform/points.mdx
index 249a346..69e70e4 100644
--- a/platform/points.mdx
+++ b/platform/points.mdx
@@ -19,9 +19,45 @@ Points systems are used to reward users for taking actions in your product. When
Use Trophy to create sophisticated points systems driven by real user interactions with no custom code.
+## Creating Points Systems
+
+Trophy let's you set up multiple points systems for different use cases within your application.
+
+
+
+
+
+To create a points system, head to the [points page](https://app.trophy.so/points) and follow the steps below.
+
+
+
+ Give the new points system a name, and a unique key. The key is what you'll
+ use to reference the points system in APIs and in email templates if
+ relevant.
+
+
+ You can also give the points system a description which is returned from
+ APIs to be displayed in your application.
+
+
+ You can also optionally upload a badge or logo to represent the points
+ system. A `src` freindly URL to the image is returned from APIs for display
+ in your application.
+
+
+
## Creating Triggers
-Points can be awarded as a result of user interactions tracked by Trophy including:
+You can add as many triggers as you like to each points system you set up in Trophy. This let's you create different logic for how points are awarded to users for different points systems.
+
+Points can be awarded as a result of many different user interactions tracked by Trophy including:
- Awarding points as users increment [Metrics](/platform/metrics) e.g. "earn 10 points for every mile ran".
- Awarding points for reaching [Streak](/platform/streaks) milestones e.g. reaching 7-day, 14-day and 30-day streaks.
@@ -38,7 +74,7 @@ Points can be awarded as a result of user interactions tracked by Trophy includi
>
-To create a new points trigger, head to the [points](https://app.trophy.so/points/configure/new) page in the Trophy dashboard and follow the steps below:
+To create a new points trigger, head to the points system that you want to create a trigger for and follow the steps below:
All new points triggers are created as 'Inactive' to allow testing and
@@ -68,6 +104,15 @@ To create a new points trigger, head to the [points](https://app.trophy.so/point
+
+ You can assign _attribute filters_ to a points trigger to further restrict when they apply.
+
+- To limit a **Metric trigger** to only apply to events with specific [custom event attributes](/platform/events#custom-event-attributes), select an attribute and enter a value in the **Event Attribute** section.
+
+- To limit any type of trigger to only apply to a user with one or more specific [custom user attributes](/platform/users#custom-user-attributes), add attributes and the desired values in the **User Attributes** section.
+
+
+
Save the new points trigger.
@@ -77,7 +122,7 @@ To create a new points trigger, head to the [points](https://app.trophy.so/point
Running an effective points system requires finding the optimal pace at which users earn points. Too fast, and users will get points fatigue, rendering them useless. Too slow, and users may get bored and churn.
-Trophy's preview tool can model different scenarios to help you determine how frequently users should earn points.
+Trophy's preview tool can model different scenarios to help you determine how frequently users should earn points in each of your points systems.