You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Changes
<!-- Please summarize your changes. -->
<!-- Please link to any applicable information (forum posts, bug
reports, etc.). -->
I added missing webhook notification types, fixed the formatting of json
and fixed the javascript example because the "replay attack prevention"
did not work at all. If there was no signature sent in the header,
validation was skipped. And if the signature was present but it was
incorrect, the function did not return.
## Checks
By submitting your pull request for review, you agree to the following:
- [x] This contribution was created in whole or in part by me, and I
have the right to submit it under the terms of this repository's open
source licenses.
- [x] I understand and agree that this contribution and a record of it
are public, maintained indefinitely, and may be redistributed under the
terms of this repository's open source licenses.
- [x] To the best of my knowledge, all proposed changes are accurate.
Co-authored-by: IgnisRBX <[email protected]>
Copy file name to clipboardExpand all lines: content/en-us/cloud/webhooks/webhook-notifications.md
+81-80Lines changed: 81 additions & 80 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,15 +19,25 @@ Once you set up a webhook, whenever a target event occurs, Roblox sends a reques
19
19
20
20
Roblox currently supports the following event triggers for notifications:
21
21
22
-
-**Subscription Cancelled** - When a user cancels a [subscription](../../production/monetization/subscriptions.md), a message is sent containing the subscription and subscriber, as well as the reason given for the cancellation.
23
-
-**Subscription Purchased** - When a user purchases a subscription, a message is sent containing the subscription and subscriber.
24
-
-**Subscription Refunded** - When a user receives a refund for their subscription, a message is sent containing the subscription and subscriber.
25
-
-**Subscription Renewed** - When a user renews a subscription, a message is sent containing the subscription and subscriber.
26
-
-**Subscription Resubscribed** - When a user resubscribes to a subscription, a message is sent containing the subscription and subscriber.
27
-
-["Right to be forgotten"](https://gdpr.eu/right-to-be-forgotten/) data deletion requests under the General Data Protection Regulation (**GDPR**).
22
+
### Subscriptions
23
+
24
+
-**Subscription Cancelled** — When a user cancels a [subscription](../../production/monetization/subscriptions.md), a message is sent containing the subscription and subscriber, as well as the reason given for the cancellation.
25
+
-**Subscription Purchased** — When a user purchases a subscription, a message is sent containing the subscription and subscriber.
26
+
-**Subscription Refunded** — When a user receives a refund for their subscription, a message is sent containing the subscription and subscriber.
27
+
-**Subscription Renewed** — When a user renews a subscription, a message is sent containing the subscription and subscriber.
28
+
-**Subscription Resubscribed** — When a user resubscribes to a subscription, a message is sent containing the subscription and subscriber.
28
29
29
30
For more information on subscription events and their fields, see the [Cloud API Subscription](../../cloud/reference/Subscription/) reference.
30
31
32
+
### Compliance
33
+
34
+
-**Right to Erasure Request** — When a user submits a data deletion request under the [General Data Protection Regulation (**GDPR**)](https://gdpr.eu/right-to-be-forgotten/).
35
+
36
+
### Commerce
37
+
38
+
-**Commerce Product Order Refunded** — When a user has recieved a refund for their commerce product order.
39
+
-**Commerce Product Order Paid** — When a user has paid for their commerce product order.
40
+
31
41
## Configure webhooks on Creator Dashboard
32
42
33
43
To receive notifications through webhooks, you need to configure a webhook that subscribes to certain events for triggering notifications. For group-owned experiences, only group owners can configure and receive webhook notifications.
@@ -41,7 +51,7 @@ To set up a webhook:
41
51
1. Navigate to the [Webhooks](https://create.roblox.com/settings/webhooks) section of the Creator Dashboard.
42
52
1. Click the **Add Webhook** button.
43
53
1. Complete the configuration fields:
44
-
1.**Webhook URL** — Specify the URL where you want to receive notifications and accept incoming webhook URLs from third-party entities. For more information on the requirements, see [Set up webhook URLs](#set-up-webhook-urls).
54
+
1.**Webhook URL** — Specify the URL where you can receive notifications. For more information on the requirements, see [Set up webhook URLs](#set-up-webhook-urls).
45
55
2.**Name** — Use a custom name to differentiate your configuration from others. By default the value is the same as the Webhook URL.
46
56
3.**Secret** (optional) — Supply a secret if you want to verify that notifications you receive are coming from Roblox. For more information, see [Verify webhook security](#verify-webhook-security).
47
57
4.**Triggers** — Choose one or more options from the list of [supported triggers](#supported-triggers) of events for which you want to receive notifications.
@@ -88,15 +98,15 @@ You can test whether the webhook you've configured can successfully receive noti
88
98
3. Click the pencil icon next to the target webhook.
89
99
4. Click the **Test Response** button.
90
100
91
-
The system then sends a notification in the `SampleNotification`type, which includes the **User ID** of the user who triggers the notification, as the following example schema shows:
101
+
A `SampleNotification`event is sent, which includes the **User ID** of the user who triggers the notification, as the following example schema shows:
92
102
93
103
```json title="SampleNotification Schema"
94
-
Body: {
104
+
{
95
105
"NotificationId": "string",
96
106
"EventType": "SampleNotification",
97
-
"EventTime": "2023-12-30T16:24:24.2118874Z",// Type: ISO 8601 Timestamp
107
+
"EventTime": "2023-12-30T16:24:24.2118874Z",
98
108
"EventPayload": {
99
-
"UserId": 1// Type: Long
109
+
"UserId": 1
100
110
}
101
111
}
102
112
```
@@ -105,19 +115,19 @@ If you are integrating your webhook with a third-party service, you can test it
105
115
106
116
## Verify webhook security
107
117
108
-
Once you configure your server to receive payloads, it starts to listen for any payload sent to the endpoint. If you set a secret when configuring your webhook, Roblox sends a `roblox-signature`along with every webhook notification to help protect your data security. This way, you can use the it to verify that the notification is from Roblox and limit your server to only receive requests originating from Roblox. The signature is in the payload header for custom endpoints and in the footer for third-party servers.
118
+
Once you configure your server to receive payloads, it starts to listen for any payload sent to the endpoint. If you set a secret when configuring your webhook, Roblox sends a `roblox-signature`in each webhook notification to ensure that the request actually came from Roblox. The signature is in the payload header for custom endpoints and in the footer for third-party servers.
109
119
110
-
```csv title="Signature Format with Secret for Custom Endpoints"
120
+
```csv title="Signature Format with a Secret for Custom Endpoints"
If you don't have a secret for your webhook, the signature you receive only contains the timestamp value on when the notification is sent:
126
+
If you did not set a secret for your webhook, the signature will only contain the timestamp of when the notification was sent:
117
127
118
-
```csv title="Signature Format without Secret for Custom Endpoints"
128
+
```csv title="Signature Format without a Secret for Custom Endpoints"
119
129
120
-
"roblox-signature": "t=<timestamp>"
130
+
t=<timestamp>
121
131
122
132
```
123
133
@@ -128,17 +138,16 @@ To verify a signature:
128
138
129
139
1. Extract the timestamp and signature values. All signatures for webhooks with secrets share the same format as a CSV string with these two values following by the prefixes:
130
140
131
-
-`t`: The timestamp value on when the notification is sent.
141
+
-`t`: The timestamp of when the notification is sent.
132
142
-`v1`: The signature value generated using the secret provided by the Creator Dashboard configuration.
133
-
You can extract these two values using the `split()` function, which separates the string based on a delimiter, in this case, the `,` character.
134
143
135
144
1. Re-create the base string of `roblox-signature` by concatenating:
136
145
137
146
1. The timestamp as a string.
138
147
1. The period character `.`.
139
148
1. The JSON string of the request body.
140
149
141
-
1. Compute a Hash-based message authentication code (HMAC) with the SHA256 hash function using the secret you defined during the configuration as the key and the base string you generated through step 2 as the message. Convert the result to Base64 format to get the expected signature.
150
+
1. Compute a hash-based message authentication code (HMAC) with the SHA256 hash function using the secret you defined during the configuration as the key and the base string you generated through step 2 as the message. Convert the result to Base64 format to get the expected signature.
142
151
1. Compare the extracted signature value to the expected signature. If you generated the signature correctly, the value should be the same.
143
152
144
153
1. (Optional) To prevent replay attacks, a type of cyber attack where attackers intercept and resend data to gain unauthorized access or perform malicious actions, it's helpful to compare the extracted timestamp value with the current timestamp and ensure it falls within a reasonable time limit. For example, a 10-minute window is usually a good reasonable time limit.
@@ -178,95 +187,87 @@ When the target event of your webhook is triggered, it sends a request to your w
178
187
179
188
The **fixed payload schema fields** can help maintain consistency across all webhook requests, with the following fields available:
180
189
181
-
1.`NotificationId`, `string`: A unique identifier for each notification sent. If the same `NotificationId` is received twice, it is considered a duplicate.
182
-
2.`EventType`, `string`: A string represents the type of event for which the notification was triggered.
183
-
3.`EventTime`, `timestamp`: An approximate timestamp indicating when the event was triggered.
190
+
1.`NotificationId` (string): A unique identifier for each notification sent. If the same `NotificationId` is received twice, it is considered a duplicate.
191
+
2.`EventType` (string): Indicates the type of event for which the notification was triggered.
192
+
3.`EventTime` (string): The timestamp of when the event was triggered.
184
193
185
194
The **variable payload schema fields** provides flexibility for webhooks to accommodate various types of events, which include:
186
195
187
-
1.`EventPayload`, `object`: Contains information specific to the `EventType` that triggered the webhook. The structure of the `EventPayload` schema varies based on the type of event.
196
+
1.`EventPayload` (object): Contains information specific to the `EventType` that triggered the webhook. The structure of the `EventPayload` schema varies based on the type of event.
188
197
189
198
The following example shows the payload schema of the **Right To Erasure Request** event:
190
199
191
200
```json title="Example Schema for Right to Erasure Request"
192
-
193
-
Body:{
194
-
201
+
{
195
202
"NotificationId": "string",
196
-
197
203
"EventType": "RightToErasureRequest",
198
-
199
204
"EventTime": "2023-12-30T16:24:24.2118874Z",
200
-
201
205
"EventPayload": {
202
-
203
-
"UserId": 1, // Type: Long
204
-
205
-
"GameIds": [ // Type: An array of Longs
206
-
206
+
"UserId": 1,
207
+
"GameIds": [
207
208
1234, 2345
208
-
209
209
]
210
-
211
210
}
212
-
213
211
}
214
212
```
215
213
216
214
## Handle notifications
217
215
218
216
If you store any **Personally Identifiable Information (PII)** of your users, such as their User IDs, you must delete this information when a user submits such a request to comply with the GDPR [right to erasure](https://gdpr-info.eu/art-17-gdpr/) compliance requirements. You can create a bot to handle webhook notifications and help automate data deletion, provided you're storing PII in a data store. See [Automating Right to Erasure Requests Deletion](../../cloud/webhooks/automate-right-to-erasure.md) for an example on how to create a bot within Guilded or Discord that uses the [Open Cloud API for data stores](../../cloud/guides/usage-data-stores.md) to delete PII data as an automation solution. This example can be adapted for handling other notifications, such as subscription events.
219
217
220
-
If you use a custom endpoint as your webhook server instead of a third-party tool, you can extract the data subject to deletion from the webhook payload and build your own automation solution. The following code sample provides an example solution and adds prevention to replay attacks by verifying that the request is coming from Roblox:
218
+
If you use a custom endpoint as your webhook server instead of a third-party tool, you can extract the data subject to deletion from the webhook payload and build your own automation solution. The following code sample is an example of a server that has prevention against replay attacks by verifying the timestamp and that the request is coming from Roblox:
221
219
222
-
```php title="Extracting PII from Payload"
223
-
const crypto = require('crypto')
220
+
```javascript title="Extracting PII from Payload"
221
+
constcrypto=require('crypto');
224
222
constexpress=require('express');
223
+
224
+
constsecret='<Your secret>'// This can be set as an environment variable
225
+
225
226
let app =express();
226
227
app.use(express.json());
227
-
app.use(express.urlencoded({ extended: true }));
228
-
// This is a sample only code
228
+
229
229
app.all('/*', function (req, res) {
230
-
console.log('-------- New Request Seen -------');
231
-
// 1. Extract the timestamp and signature
232
-
const shared_secret = '<Yoursecret>' // This can be set as an environment variable
0 commit comments