@walkeros/server-destination-reddit 3.4.0-next-1776749829492

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/push.ts","../src/hash.ts","../src/types/index.ts","../src/index.ts"],"sourcesContent":["import type { Config, Settings, PartialConfig } from './types';\nimport type { Logger } from '@walkeros/core';\n\nexport function getConfig(\n partialConfig: PartialConfig = {},\n logger: Logger.Instance,\n): Config {\n const settings = (partialConfig.settings || {}) as Partial<Settings>;\n const { accessToken, pixelId } = settings;\n\n if (!accessToken) logger.throw('Config settings accessToken missing');\n if (!pixelId) logger.throw('Config settings pixelId missing');\n\n const settingsConfig: Settings = {\n ...settings,\n accessToken,\n pixelId,\n };\n\n return { ...partialConfig, settings: settingsConfig };\n}\n","import type {\n ConversionEvent,\n EventType,\n PushFn,\n RequestBody,\n TrackingType,\n UserData,\n} from './types';\nimport { getMappingValue, isObject } from '@walkeros/core';\nimport { sendServer } from '@walkeros/server-core';\nimport { hashEvent } from './hash';\n\nconst STANDARD_TRACKING_TYPES: ReadonlySet<TrackingType> =\n new Set<TrackingType>([\n 'PageVisit',\n 'ViewContent',\n 'Search',\n 'AddToCart',\n 'AddToWishlist',\n 'Purchase',\n 'Lead',\n 'SignUp',\n 'Custom',\n ]);\n\nfunction isStandardTrackingType(name: string): name is TrackingType {\n return STANDARD_TRACKING_TYPES.has(name as TrackingType);\n}\n\nfunction buildEventType(name: string): EventType {\n if (isStandardTrackingType(name) && name !== 'Custom') {\n return { tracking_type: name };\n }\n return { tracking_type: 'Custom', custom_event_name: name };\n}\n\nexport const push: PushFn = async function (\n event,\n { config, data, env, logger },\n) {\n const {\n accessToken,\n pixelId,\n action_source: _action_source,\n doNotHash,\n test_mode,\n url = 'https://ads-api.reddit.com/api/v2.0/conversions/events/',\n user_data,\n } = config.settings!;\n\n const eventData = isObject(data) ? data : {};\n const configData = config.data\n ? await getMappingValue(event, config.data)\n : {};\n const userDataCustom = user_data\n ? await getMappingValue(event, { map: user_data })\n : {};\n\n // Merge user data from config.data, settings.user_data, and event mapping\n const userData: UserData = {\n ...(isObject(configData) && isObject(configData.user)\n ? configData.user\n : {}),\n ...(isObject(userDataCustom) ? userDataCustom : {}),\n ...(isObject(eventData.user) ? eventData.user : {}),\n };\n\n const {\n user: _u,\n event_metadata: eventMetadata,\n click_id: eventClickId,\n ...restEventData\n } = eventData;\n\n const timestampMs = event.timestamp || Date.now();\n\n const serverEvent: ConversionEvent = {\n event_at: new Date(timestampMs).toISOString(),\n event_at_ms: timestampMs,\n event_type: buildEventType(event.name),\n ...restEventData,\n user: userData,\n };\n\n // Merge event_metadata with auto-populated conversion_id (event.id for dedup)\n const metadataFromMapping = isObject(eventMetadata) ? eventMetadata : {};\n serverEvent.event_metadata = {\n conversion_id: event.id,\n ...metadataFromMapping,\n };\n\n if (typeof eventClickId === 'string') {\n serverEvent.click_id = eventClickId;\n }\n\n const hashedServerEvent = await hashEvent(serverEvent, doNotHash);\n\n const body: RequestBody = {\n ...(test_mode ? { test_mode: true } : {}),\n data: { events: [hashedServerEvent] },\n };\n\n const endpoint = `${url}${pixelId}`;\n\n logger.debug('Calling Reddit API', {\n endpoint,\n method: 'POST',\n trackingType: serverEvent.event_type.tracking_type,\n eventId: serverEvent.event_metadata?.conversion_id,\n });\n\n const sendServerFn = env?.sendServer || sendServer;\n const result = await sendServerFn(endpoint, JSON.stringify(body), {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n\n logger.debug('Reddit API response', {\n ok: isObject(result) ? result.ok : true,\n });\n\n if (isObject(result) && result.ok === false) {\n logger.throw(`Reddit API error: ${JSON.stringify(result)}`);\n }\n};\n","import { WalkerOS } from '@walkeros/core';\nimport { isArray, isObject, isString } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\n\nconst keysToHash = [\n 'email',\n 'external_id',\n 'ip_address',\n 'user_agent',\n 'idfa',\n 'aaid',\n];\n\nfunction shouldBeHashed(key: string, doNotHash: string[] = []): boolean {\n return keysToHash.includes(key) && !doNotHash.includes(key);\n}\n\ntype HashableValue = WalkerOS.AnyObject | unknown | unknown[];\n\nasync function processValue(\n value: unknown,\n shouldHash: boolean,\n): Promise<unknown> {\n if (!shouldHash) return value;\n if (isArray(value)) {\n return Promise.all(value.map((item) => getHashServer(String(item))));\n }\n return getHashServer(String(value));\n}\n\nexport async function hashEvent<T extends HashableValue>(\n value: T,\n doNotHash: string[] = [],\n): Promise<T> {\n if (!isObject(value)) return value;\n\n const isUser = 'user' in value;\n const target = (isUser ? value.user : value) as WalkerOS.AnyObject;\n\n const entries = await Promise.all(\n Object.entries(target).map(async ([k, v]) => [\n k,\n await processValue(v, isUser && shouldBeHashed(k, doNotHash)),\n ]),\n );\n\n const result = entries.reduce((acc, [k, v]) => {\n if (isString(k)) acc[k] = v;\n return acc;\n }, {} as WalkerOS.AnyObject);\n\n return isUser ? { ...value, user: result } : (result as T);\n}\n","import type {\n Mapping as WalkerOSMapping,\n Destination as CoreDestination,\n} from '@walkeros/core';\nimport type { DestinationServer, sendServer } from '@walkeros/server-core';\n\nexport interface Settings {\n accessToken: string;\n pixelId: string;\n action_source?: ActionSource;\n doNotHash?: string[];\n test_mode?: boolean;\n url?: string;\n user_data?: WalkerOSMapping.Map;\n}\n\nexport type InitSettings = Partial<Settings>;\n\nexport interface Mapping {}\n\nexport interface Env extends DestinationServer.Env {\n sendServer?: typeof sendServer;\n}\n\nexport type Types = CoreDestination.Types<Settings, Mapping, Env, InitSettings>;\n\nexport interface Destination extends DestinationServer.Destination<Types> {\n init: DestinationServer.InitFn<Types>;\n}\n\nexport type Config = {\n settings: Settings;\n} & DestinationServer.Config<Types>;\n\nexport type InitFn = DestinationServer.InitFn<Types>;\nexport type PushFn = DestinationServer.PushFn<Types>;\n\nexport type PartialConfig = DestinationServer.PartialConfig<Types>;\n\nexport type PushEvents = DestinationServer.PushEvents<Mapping>;\n\nexport type Rule = WalkerOSMapping.Rule<Mapping>;\nexport type Rules = WalkerOSMapping.Rules<Rule>;\n\n// Reddit Conversions API types\n// https://ads-api.reddit.com/docs/v2/#tag/Conversions-API\n\nexport type ActionSource = 'WEBSITE' | 'APP' | 'PHYSICAL_STORE';\n\nexport type TrackingType =\n | 'PageVisit'\n | 'ViewContent'\n | 'Search'\n | 'AddToCart'\n | 'AddToWishlist'\n | 'Purchase'\n | 'Lead'\n | 'SignUp'\n | 'Custom';\n\nexport interface EventType {\n tracking_type: TrackingType;\n custom_event_name?: string;\n}\n\nexport interface Product {\n id: string;\n name?: string;\n category: string;\n}\n\nexport interface EventMetadata {\n conversion_id?: string;\n item_count?: number;\n currency?: string;\n value?: number;\n value_decimal?: number;\n products?: Product[];\n units_sold?: number;\n country_code?: string;\n}\n\nexport interface ScreenDimensions {\n width: number;\n height: number;\n}\n\nexport interface DataProcessingOptions {\n modes: string[];\n country?: string;\n region?: string;\n}\n\nexport interface UserData {\n // Hashable fields (SHA-256)\n email?: string;\n external_id?: string;\n ip_address?: string;\n user_agent?: string;\n idfa?: string;\n aaid?: string;\n\n // Pass-through fields (not hashed)\n uuid?: string;\n opt_out?: boolean;\n screen_dimensions?: ScreenDimensions;\n data_processing_options?: DataProcessingOptions;\n}\n\nexport interface ConversionEvent {\n click_id?: string;\n event_at: string;\n event_at_ms?: number;\n event_type: EventType;\n event_metadata?: EventMetadata;\n user: UserData;\n}\n\nexport interface RequestBody {\n test_mode?: boolean;\n data: {\n events: ConversionEvent[];\n };\n}\n\nexport interface ResponseBody {\n success?: boolean;\n message?: string;\n}\n","import type { Destination } from './types';\nimport { getConfig } from './config';\nimport { push } from './push';\n\n// Types\nexport * as DestinationReddit from './types';\n\nexport const destinationReddit: Destination = {\n type: 'reddit',\n\n config: {},\n\n async init({ config: partialConfig, logger }) {\n const config = getConfig(partialConfig, logger);\n return config;\n },\n\n async push(event, context) {\n return await push(event, context);\n },\n};\n\nexport default destinationReddit;\n"],"mappings":"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","names":["isObject","isObject"]}
@@ -0,0 +1,621 @@
1
+ {
2
+ "$meta": {
3
+ "package": "@walkeros/server-destination-reddit",
4
+ "version": "3.4.0-next-1776749829492",
5
+ "type": "destination",
6
+ "platform": [
7
+ "server"
8
+ ],
9
+ "docs": "https://www.walkeros.io/docs/destinations/server/reddit",
10
+ "source": "https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/reddit/src"
11
+ },
12
+ "schemas": {
13
+ "mapping": {
14
+ "$schema": "http://json-schema.org/draft-07/schema#",
15
+ "type": "object",
16
+ "properties": {},
17
+ "additionalProperties": false
18
+ },
19
+ "settings": {
20
+ "$schema": "http://json-schema.org/draft-07/schema#",
21
+ "type": "object",
22
+ "properties": {
23
+ "accessToken": {
24
+ "type": "string",
25
+ "minLength": 1,
26
+ "description": "Reddit Conversion Access Token for Bearer authentication (like rdt_ABC123...)"
27
+ },
28
+ "pixelId": {
29
+ "type": "string",
30
+ "minLength": 1,
31
+ "description": "Reddit Pixel ID used as the API path parameter (like a2_abcdef123456)"
32
+ },
33
+ "action_source": {
34
+ "type": "string",
35
+ "enum": [
36
+ "WEBSITE",
37
+ "APP",
38
+ "PHYSICAL_STORE"
39
+ ],
40
+ "description": "Source of the event (WEBSITE, APP, PHYSICAL_STORE) (like WEBSITE)"
41
+ },
42
+ "doNotHash": {
43
+ "type": "array",
44
+ "items": {
45
+ "type": "string"
46
+ },
47
+ "description": "Array of user fields that should not be hashed (like ['email'])"
48
+ },
49
+ "test_mode": {
50
+ "type": "boolean",
51
+ "description": "Enable test mode by sending test_mode: true in the request body (like true)"
52
+ },
53
+ "url": {
54
+ "type": "string",
55
+ "format": "uri",
56
+ "description": "Custom URL for Reddit Conversions API endpoint (like https://ads-api.reddit.com/api/v2.0/conversions/events/)"
57
+ },
58
+ "user_data": {
59
+ "type": "object",
60
+ "propertyNames": {
61
+ "type": "string"
62
+ },
63
+ "additionalProperties": {
64
+ "type": "string"
65
+ },
66
+ "description": "Mapping configuration for user fields (like { email: 'user.email', external_id: 'user.id' })"
67
+ }
68
+ },
69
+ "required": [
70
+ "accessToken",
71
+ "pixelId"
72
+ ],
73
+ "additionalProperties": false
74
+ }
75
+ },
76
+ "examples": {
77
+ "env": {
78
+ "push": {
79
+ "sendServer": {
80
+ "$code": "async()=>({ok:!0,data:{success:!0}})"
81
+ }
82
+ },
83
+ "simulation": [
84
+ "sendServer"
85
+ ]
86
+ },
87
+ "step": {
88
+ "addToCart": {
89
+ "in": {
90
+ "name": "product add",
91
+ "data": {
92
+ "id": "SKU-B2",
93
+ "name": "Cool Cap",
94
+ "category": "hats",
95
+ "price": "42.00",
96
+ "quantity": 1
97
+ },
98
+ "context": {
99
+ "shopping": [
100
+ "intent",
101
+ 0
102
+ ]
103
+ },
104
+ "globals": {
105
+ "pagegroup": "shop"
106
+ },
107
+ "custom": {
108
+ "completely": "random"
109
+ },
110
+ "user": {
111
+ "id": "user-456"
112
+ },
113
+ "nested": [],
114
+ "consent": {
115
+ "functional": true
116
+ },
117
+ "id": "1700000901-gr0up-1",
118
+ "trigger": "click",
119
+ "entity": "product",
120
+ "action": "add",
121
+ "timestamp": 1700000901,
122
+ "timing": 3.14,
123
+ "group": "gr0up",
124
+ "count": 1,
125
+ "version": {
126
+ "source": "3.4.0-next-1776749829492",
127
+ "tagging": 1
128
+ },
129
+ "source": {
130
+ "type": "server",
131
+ "id": "https://shop.example.com/products",
132
+ "previous_id": ""
133
+ }
134
+ },
135
+ "mapping": {
136
+ "name": "AddToCart",
137
+ "data": {
138
+ "map": {
139
+ "event_metadata": {
140
+ "map": {
141
+ "value_decimal": "data.price",
142
+ "currency": {
143
+ "value": "EUR"
144
+ },
145
+ "item_count": {
146
+ "value": 1
147
+ },
148
+ "products": {
149
+ "set": [
150
+ {
151
+ "map": {
152
+ "id": "data.id",
153
+ "name": "data.name",
154
+ "category": {
155
+ "key": "data.category",
156
+ "value": "uncategorized"
157
+ }
158
+ }
159
+ }
160
+ ]
161
+ }
162
+ }
163
+ }
164
+ }
165
+ }
166
+ },
167
+ "out": [
168
+ [
169
+ "sendServer",
170
+ "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
171
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.901Z\",\"event_at_ms\":1700000901,\"event_type\":{\"tracking_type\":\"AddToCart\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000901-gr0up-1\",\"value_decimal\":\"42.00\",\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-B2\",\"name\":\"Cool Cap\",\"category\":\"hats\"}]}}]}}",
172
+ {
173
+ "headers": {
174
+ "Authorization": "Bearer s3cr3t"
175
+ }
176
+ }
177
+ ]
178
+ ]
179
+ },
180
+ "lead": {
181
+ "in": {
182
+ "name": "form submit",
183
+ "data": {
184
+ "form": "contact"
185
+ },
186
+ "context": {
187
+ "dev": [
188
+ "test",
189
+ 1
190
+ ]
191
+ },
192
+ "globals": {
193
+ "lang": "elb"
194
+ },
195
+ "custom": {
196
+ "completely": "random"
197
+ },
198
+ "user": {
199
+ "id": "user-lead-1",
200
+ "email": "lead@example.com"
201
+ },
202
+ "nested": [
203
+ {
204
+ "entity": "child",
205
+ "data": {
206
+ "is": "subordinated"
207
+ },
208
+ "nested": [],
209
+ "context": {
210
+ "element": [
211
+ "child",
212
+ 0
213
+ ]
214
+ }
215
+ }
216
+ ],
217
+ "consent": {
218
+ "functional": true
219
+ },
220
+ "id": "1700000903-gr0up-1",
221
+ "trigger": "test",
222
+ "entity": "form",
223
+ "action": "submit",
224
+ "timestamp": 1700000903,
225
+ "timing": 3.14,
226
+ "group": "gr0up",
227
+ "count": 1,
228
+ "version": {
229
+ "source": "3.4.0-next-1776749829492",
230
+ "tagging": 1
231
+ },
232
+ "source": {
233
+ "type": "server",
234
+ "id": "https://www.example.com/contact",
235
+ "previous_id": ""
236
+ }
237
+ },
238
+ "mapping": {
239
+ "name": "Lead",
240
+ "data": {
241
+ "map": {
242
+ "user": {
243
+ "map": {
244
+ "email": "user.email",
245
+ "external_id": "user.id"
246
+ }
247
+ }
248
+ }
249
+ }
250
+ },
251
+ "out": [
252
+ [
253
+ "sendServer",
254
+ "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
255
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.903Z\",\"event_at_ms\":1700000903,\"event_type\":{\"tracking_type\":\"Lead\"},\"user\":{\"email\":\"9fbdefe2837a03c9225be80e741f316f4d174d1732b719b6abb6477efc1ae9d2\",\"external_id\":\"ee818eebb052cf288ffeeb2e09ee35c9946e1a7f53a959cb3ef06d5d4adb78e8\"},\"event_metadata\":{\"conversion_id\":\"1700000903-gr0up-1\"}}]}}",
256
+ {
257
+ "headers": {
258
+ "Authorization": "Bearer s3cr3t"
259
+ }
260
+ }
261
+ ]
262
+ ]
263
+ },
264
+ "pageVisit": {
265
+ "in": {
266
+ "name": "page view",
267
+ "data": {
268
+ "domain": "www.example.com",
269
+ "title": "walkerOS documentation",
270
+ "referrer": "https://www.walkeros.io/",
271
+ "search": "?foo=bar",
272
+ "hash": "#hash",
273
+ "id": "/docs/"
274
+ },
275
+ "context": {
276
+ "dev": [
277
+ "test",
278
+ 1
279
+ ]
280
+ },
281
+ "globals": {
282
+ "pagegroup": "docs"
283
+ },
284
+ "custom": {
285
+ "completely": "random"
286
+ },
287
+ "user": {
288
+ "id": "user-789"
289
+ },
290
+ "nested": [
291
+ {
292
+ "entity": "child",
293
+ "data": {
294
+ "is": "subordinated"
295
+ },
296
+ "nested": [],
297
+ "context": {
298
+ "element": [
299
+ "child",
300
+ 0
301
+ ]
302
+ }
303
+ }
304
+ ],
305
+ "consent": {
306
+ "functional": true
307
+ },
308
+ "id": "1700000902-gr0up-1",
309
+ "trigger": "load",
310
+ "entity": "page",
311
+ "action": "view",
312
+ "timestamp": 1700000902,
313
+ "timing": 3.14,
314
+ "group": "gr0up",
315
+ "count": 1,
316
+ "version": {
317
+ "source": "3.4.0-next-1776749829492",
318
+ "tagging": 1
319
+ },
320
+ "source": {
321
+ "type": "server",
322
+ "id": "https://www.example.com/docs/",
323
+ "previous_id": ""
324
+ }
325
+ },
326
+ "mapping": {
327
+ "name": "PageVisit"
328
+ },
329
+ "out": [
330
+ [
331
+ "sendServer",
332
+ "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
333
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.902Z\",\"event_at_ms\":1700000902,\"event_type\":{\"tracking_type\":\"PageVisit\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000902-gr0up-1\"}}]}}",
334
+ {
335
+ "headers": {
336
+ "Authorization": "Bearer s3cr3t"
337
+ }
338
+ }
339
+ ]
340
+ ]
341
+ },
342
+ "purchase": {
343
+ "in": {
344
+ "name": "order complete",
345
+ "data": {
346
+ "id": "ORD-300",
347
+ "total": 249.99,
348
+ "currency": "EUR"
349
+ },
350
+ "context": {
351
+ "shopping": [
352
+ "complete",
353
+ 0
354
+ ]
355
+ },
356
+ "globals": {
357
+ "pagegroup": "shop"
358
+ },
359
+ "custom": {
360
+ "completely": "random"
361
+ },
362
+ "user": {
363
+ "id": "user-123",
364
+ "device": "device-456"
365
+ },
366
+ "nested": [
367
+ {
368
+ "entity": "product",
369
+ "data": {
370
+ "id": "SKU-A1",
371
+ "name": "Everyday Ruck Snack",
372
+ "category": "bags",
373
+ "price": "129.99",
374
+ "quantity": 2
375
+ }
376
+ }
377
+ ],
378
+ "consent": {
379
+ "functional": true
380
+ },
381
+ "id": "1700000900-gr0up-1",
382
+ "trigger": "load",
383
+ "entity": "order",
384
+ "action": "complete",
385
+ "timestamp": 1700000900,
386
+ "timing": 3.14,
387
+ "group": "gr0up",
388
+ "count": 1,
389
+ "version": {
390
+ "source": "3.4.0-next-1776749829492",
391
+ "tagging": 1
392
+ },
393
+ "source": {
394
+ "type": "server",
395
+ "id": "https://shop.example.com",
396
+ "previous_id": ""
397
+ }
398
+ },
399
+ "mapping": {
400
+ "name": "Purchase",
401
+ "data": {
402
+ "map": {
403
+ "event_metadata": {
404
+ "map": {
405
+ "value_decimal": "data.total",
406
+ "currency": {
407
+ "key": "data.currency",
408
+ "value": "EUR"
409
+ },
410
+ "item_count": {
411
+ "fn": {
412
+ "$code": "e=>e.nested.filter(e=>\"product\"===e.entity).length"
413
+ }
414
+ },
415
+ "products": {
416
+ "loop": [
417
+ "nested",
418
+ {
419
+ "condition": {
420
+ "$code": "e=>h(e)&&\"product\"===e.entity"
421
+ },
422
+ "map": {
423
+ "id": "data.id",
424
+ "name": "data.name",
425
+ "category": {
426
+ "key": "data.category",
427
+ "value": "uncategorized"
428
+ }
429
+ }
430
+ }
431
+ ]
432
+ }
433
+ }
434
+ }
435
+ }
436
+ }
437
+ },
438
+ "out": [
439
+ [
440
+ "sendServer",
441
+ "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
442
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.900Z\",\"event_at_ms\":1700000900,\"event_type\":{\"tracking_type\":\"Purchase\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000900-gr0up-1\",\"value_decimal\":249.99,\"currency\":\"EUR\",\"item_count\":1,\"products\":[{\"id\":\"SKU-A1\",\"name\":\"Everyday Ruck Snack\",\"category\":\"bags\"}]}}]}}",
443
+ {
444
+ "headers": {
445
+ "Authorization": "Bearer s3cr3t"
446
+ }
447
+ }
448
+ ]
449
+ ]
450
+ },
451
+ "search": {
452
+ "in": {
453
+ "name": "site search",
454
+ "data": {
455
+ "query": "walkerOS destinations"
456
+ },
457
+ "context": {
458
+ "dev": [
459
+ "test",
460
+ 1
461
+ ]
462
+ },
463
+ "globals": {
464
+ "lang": "elb"
465
+ },
466
+ "custom": {
467
+ "completely": "random"
468
+ },
469
+ "user": {
470
+ "id": "user-101"
471
+ },
472
+ "nested": [
473
+ {
474
+ "entity": "child",
475
+ "data": {
476
+ "is": "subordinated"
477
+ },
478
+ "nested": [],
479
+ "context": {
480
+ "element": [
481
+ "child",
482
+ 0
483
+ ]
484
+ }
485
+ }
486
+ ],
487
+ "consent": {
488
+ "functional": true
489
+ },
490
+ "id": "1700000905-gr0up-1",
491
+ "trigger": "test",
492
+ "entity": "site",
493
+ "action": "search",
494
+ "timestamp": 1700000905,
495
+ "timing": 3.14,
496
+ "group": "gr0up",
497
+ "count": 1,
498
+ "version": {
499
+ "source": "3.4.0-next-1776749829492",
500
+ "tagging": 1
501
+ },
502
+ "source": {
503
+ "type": "server",
504
+ "id": "https://www.example.com/search",
505
+ "previous_id": ""
506
+ }
507
+ },
508
+ "mapping": {
509
+ "name": "Search",
510
+ "data": {
511
+ "map": {
512
+ "event_metadata": {
513
+ "map": {
514
+ "item_count": {
515
+ "value": 1
516
+ }
517
+ }
518
+ }
519
+ }
520
+ }
521
+ },
522
+ "out": [
523
+ [
524
+ "sendServer",
525
+ "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
526
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.905Z\",\"event_at_ms\":1700000905,\"event_type\":{\"tracking_type\":\"Search\"},\"user\":{},\"event_metadata\":{\"conversion_id\":\"1700000905-gr0up-1\",\"item_count\":1}}]}}",
527
+ {
528
+ "headers": {
529
+ "Authorization": "Bearer s3cr3t"
530
+ }
531
+ }
532
+ ]
533
+ ]
534
+ },
535
+ "signUp": {
536
+ "in": {
537
+ "name": "user signup",
538
+ "data": {
539
+ "method": "email"
540
+ },
541
+ "context": {
542
+ "dev": [
543
+ "test",
544
+ 1
545
+ ]
546
+ },
547
+ "globals": {
548
+ "lang": "elb"
549
+ },
550
+ "custom": {
551
+ "completely": "random"
552
+ },
553
+ "user": {
554
+ "id": "new-user-1",
555
+ "email": "new@example.com"
556
+ },
557
+ "nested": [
558
+ {
559
+ "entity": "child",
560
+ "data": {
561
+ "is": "subordinated"
562
+ },
563
+ "nested": [],
564
+ "context": {
565
+ "element": [
566
+ "child",
567
+ 0
568
+ ]
569
+ }
570
+ }
571
+ ],
572
+ "consent": {
573
+ "functional": true
574
+ },
575
+ "id": "1700000904-gr0up-1",
576
+ "trigger": "test",
577
+ "entity": "user",
578
+ "action": "signup",
579
+ "timestamp": 1700000904,
580
+ "timing": 3.14,
581
+ "group": "gr0up",
582
+ "count": 1,
583
+ "version": {
584
+ "source": "3.4.0-next-1776749829492",
585
+ "tagging": 1
586
+ },
587
+ "source": {
588
+ "type": "server",
589
+ "id": "https://www.example.com/register",
590
+ "previous_id": ""
591
+ }
592
+ },
593
+ "mapping": {
594
+ "name": "SignUp",
595
+ "data": {
596
+ "map": {
597
+ "user": {
598
+ "map": {
599
+ "email": "user.email",
600
+ "external_id": "user.id"
601
+ }
602
+ }
603
+ }
604
+ }
605
+ },
606
+ "out": [
607
+ [
608
+ "sendServer",
609
+ "https://ads-api.reddit.com/api/v2.0/conversions/events/a2_abcdef123456",
610
+ "{\"data\":{\"events\":[{\"event_at\":\"1970-01-20T16:13:20.904Z\",\"event_at_ms\":1700000904,\"event_type\":{\"tracking_type\":\"SignUp\"},\"user\":{\"email\":\"f0030501023327437b06e5c6f87df7871b8e704ae608d1d0b7b24fdd2a06c716\",\"external_id\":\"b45cf5f6ebc2c6974ea3bd9fab19f8cc3a7cf63054727a9fcd22f1fda97d6dde\"},\"event_metadata\":{\"conversion_id\":\"1700000904-gr0up-1\"}}]}}",
611
+ {
612
+ "headers": {
613
+ "Authorization": "Bearer s3cr3t"
614
+ }
615
+ }
616
+ ]
617
+ ]
618
+ }
619
+ }
620
+ }
621
+ }