@pipedream/linkedin_ads 0.2.0 → 0.3.1

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.
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # Overview
2
+
3
+ The LinkedIn Ads API on Pipedream enables you to automate and integrate your LinkedIn advertising efforts with other services. Fetch campaign data, manage ad accounts, or automate ad creation and adjustments. With Pipedream, you can trigger workflows with HTTP requests, emails, and on a schedule, and connect to thousands of other apps with minimal effort.
4
+
5
+ # Example Use Cases
6
+
7
+ - **Sync LinkedIn Ad Campaigns to Google Sheets**: Automate the syncing of LinkedIn Ad campaign data into a Google Sheets spreadsheet. This workflow makes it easy to analyze ad performance, share reports with your team, and maintain records without manual data entry.
8
+
9
+ - **LinkedIn Ad Performance Alerts via Slack or Email**: Set up a workflow that monitors your LinkedIn Ad campaigns for key performance metrics, and sends an alert via Slack or Email when your ads meet certain criteria, such as cost per click (CPC) thresholds or impressions goals, ensuring prompt reaction to ad performance.
10
+
11
+ - **Automatic Ad Pausing Based on Budget Constraints**: Create a workflow that checks your LinkedIn Ad spend against your set budget and automatically pauses campaigns if spend exceeds your budget. This helps maintain control over your advertising costs without needing to check in manually.
@@ -0,0 +1,62 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import app from "../../linkedin_ads.app.mjs";
3
+ import utils from "../../common/utils.mjs";
4
+
5
+ export default {
6
+ props: {
7
+ app,
8
+ },
9
+ methods: {
10
+ getDateStr(date) {
11
+ return [
12
+ `day:${date.getDate()}`,
13
+ `month:${date.getMonth() + 1}`,
14
+ `year:${date.getFullYear()}`,
15
+ ].join(",");
16
+ },
17
+ getDateRangeParam(startStr, endStr) {
18
+ const { getDateStr } = this;
19
+ const start = getDateStr(new Date(startStr));
20
+
21
+ if (!endStr) {
22
+ return `(start:(${start}))`;
23
+ }
24
+
25
+ const end = getDateStr(new Date(endStr));
26
+ return `(start:(${start}),end:(${end}))`;
27
+ },
28
+ getListParam(list = []) {
29
+ return `List(${list?.map(encodeURIComponent).join(",")})`;
30
+ },
31
+ getListParams(props = {}) {
32
+ return Object.entries(props)
33
+ .reduce((acc, [
34
+ key,
35
+ value,
36
+ ]) => {
37
+ if (
38
+ typeof(value) === "function"
39
+ || value === undefined
40
+ || value === null
41
+ ) {
42
+ return acc;
43
+ }
44
+ return {
45
+ ...acc,
46
+ [key]: this.getListParam(
47
+ typeof(value) === "string"
48
+ ? JSON.parse(value)
49
+ : value,
50
+ ),
51
+ };
52
+ }, {});
53
+ },
54
+ createReport(args = {}) {
55
+ return this.app._makeRequest({
56
+ path: "/adAnalytics",
57
+ paramsSerializer: utils.getParamsSerializer(),
58
+ ...args,
59
+ });
60
+ },
61
+ },
62
+ };
@@ -0,0 +1,105 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import common from "../common/report.mjs";
3
+
4
+ export default {
5
+ ...common,
6
+ key: "linkedin_ads-create-report",
7
+ name: "Create A Report",
8
+ description: "Queries the Analytics Finder to get analytics for the specified entity i.e company, account, campaign. [See the docs here](https://docs.microsoft.com/en-us/linkedin/marketing/integrations/ads-reporting/ads-reporting#analytics-finder)",
9
+ version: "0.0.4",
10
+ type: "action",
11
+ props: {
12
+ ...common.props,
13
+ adAccountId: {
14
+ propDefinition: [
15
+ common.props.app,
16
+ "adAccountId",
17
+ ],
18
+ },
19
+ pivot: {
20
+ propDefinition: [
21
+ common.props.app,
22
+ "pivot",
23
+ ],
24
+ },
25
+ timeGranularity: {
26
+ propDefinition: [
27
+ common.props.app,
28
+ "timeGranularity",
29
+ ],
30
+ },
31
+ dateRangeStart: {
32
+ type: "string",
33
+ label: "Date Range Start",
34
+ description: "Represents the inclusive start time range of the analytics. If unset, it indicates an open range up to the end time. Should be in the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format, e.g. 2022-12-27.",
35
+ },
36
+ dateRangeEnd: {
37
+ type: "string",
38
+ label: "Date Range End",
39
+ description: "Represents the inclusive end time range of the analytics. Must be after start time if it's present. If unset, it indicates an open range from start time to everything after. Should be in the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format, e.g. 2022-12-27.",
40
+ optional: true,
41
+ },
42
+ shares: {
43
+ type: "string[]",
44
+ label: "Shares",
45
+ description: "An [Array of Share URN](https://docs.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/share-api). Required unless another facet is provided.",
46
+ optional: true,
47
+ },
48
+ campaigns: {
49
+ type: "string[]",
50
+ label: "Campaigns",
51
+ description: "An [Array of Sponsored Campaign URN](https://docs.microsoft.com/en-us/linkedin/shared/references/v2/ads/adcampaigns?context=linkedin/marketing/context). Required unless another facet is provided.",
52
+ optional: true,
53
+ },
54
+ creatives: {
55
+ type: "string[]",
56
+ label: "Creatives",
57
+ description: "An [Array of Sponsored Creative URN](https://docs.microsoft.com/en-us/linkedin/shared/references/v2/ads/adcreatives?context=linkedin/marketing/context). Required unless another facet is provided.",
58
+ optional: true,
59
+ },
60
+ campaignGroups: {
61
+ type: "string[]",
62
+ label: "Campaign Groups",
63
+ description: "An [Array of Campaign Group URN](https://docs.microsoft.com/en-us/linkedin/shared/references/v2/ads/adcampaigngroups?context=linkedin/marketing/context). Required unless another facet is provided.",
64
+ optional: true,
65
+ },
66
+ accounts: {
67
+ propDefinition: [
68
+ common.props.app,
69
+ "accounts",
70
+ ({ adAccountId }) => ({
71
+ adAccountId,
72
+ }),
73
+ ],
74
+ },
75
+ },
76
+ async run({ $ }) {
77
+ const {
78
+ app,
79
+ getDateRangeParam,
80
+ getListParams,
81
+ createReport,
82
+ adAccountId,
83
+ pivot,
84
+ timeGranularity,
85
+ dateRangeStart,
86
+ dateRangeEnd,
87
+ ...arrayProps
88
+ } = this;
89
+
90
+ const response = await createReport({
91
+ $,
92
+ params: {
93
+ q: "analytics",
94
+ pivot,
95
+ timeGranularity,
96
+ dateRange: getDateRangeParam(dateRangeStart, dateRangeEnd),
97
+ ...getListParams(arrayProps),
98
+ },
99
+ });
100
+
101
+ $.export("$summary", `Successfully retrieved analytics information with ${response.elements.length} elements.`);
102
+
103
+ return response.elements;
104
+ },
105
+ };
@@ -0,0 +1,60 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import common from "../common/report.mjs";
3
+
4
+ export default {
5
+ ...common,
6
+ key: "linkedin_ads-create-report-by-advertiser-account",
7
+ name: "Create Report By Advertiser Account",
8
+ description: "Sample query using analytics finder that gets analytics for a particular account for date range starting in a given year. [See the docs here](https://docs.microsoft.com/en-us/linkedin/marketing/integrations/ads-reporting/ads-reporting#sample-request)",
9
+ version: "0.0.4",
10
+ type: "action",
11
+ props: {
12
+ ...common.props,
13
+ startYear: {
14
+ propDefinition: [
15
+ common.props.app,
16
+ "startYear",
17
+ ],
18
+ },
19
+ timeGranularity: {
20
+ propDefinition: [
21
+ common.props.app,
22
+ "timeGranularity",
23
+ ],
24
+ },
25
+ adAccountId: {
26
+ propDefinition: [
27
+ common.props.app,
28
+ "adAccountId",
29
+ ],
30
+ },
31
+ },
32
+ async run({ $ }) {
33
+ const {
34
+ app,
35
+ getDateRangeParam,
36
+ startYear,
37
+ timeGranularity,
38
+ adAccountId,
39
+ getListParam,
40
+ createReport,
41
+ } = this;
42
+
43
+ const response = await createReport({
44
+ $,
45
+ params: {
46
+ "q": "analytics",
47
+ "pivot": "ACCOUNT",
48
+ "dateRange": getDateRangeParam(`${startYear}-01-01`),
49
+ timeGranularity,
50
+ "accounts": getListParam([
51
+ app.getSponsoredAccountUrn(adAccountId),
52
+ ]),
53
+ },
54
+ });
55
+
56
+ $.export("$summary", "Successfully retrieved analytics");
57
+
58
+ return response;
59
+ },
60
+ };
@@ -0,0 +1,69 @@
1
+ /* eslint-disable no-unused-vars */
2
+ import common from "../common/report.mjs";
3
+
4
+ export default {
5
+ ...common,
6
+ key: "linkedin_ads-create-report-by-campaign",
7
+ name: "Query Analytics Finder Campaign Sample",
8
+ description: "Sample query using analytics finder that gets analytics for a particular campaign in a date range starting in a given year. [See the docs here](https://docs.microsoft.com/en-us/linkedin/marketing/integrations/ads-reporting/ads-reporting#analytics-finder)",
9
+ version: "0.0.4",
10
+ type: "action",
11
+ props: {
12
+ ...common.props,
13
+ startYear: {
14
+ propDefinition: [
15
+ common.props.app,
16
+ "startYear",
17
+ ],
18
+ },
19
+ timeGranularity: {
20
+ propDefinition: [
21
+ common.props.app,
22
+ "timeGranularity",
23
+ ],
24
+ },
25
+ adAccountId: {
26
+ propDefinition: [
27
+ common.props.app,
28
+ "adAccountId",
29
+ ],
30
+ },
31
+ campaignId: {
32
+ propDefinition: [
33
+ common.props.app,
34
+ "campaignId",
35
+ ({ adAccountId }) => ({
36
+ adAccountId,
37
+ }),
38
+ ],
39
+ },
40
+ },
41
+ async run({ $ }) {
42
+ const {
43
+ app,
44
+ getDateRangeParam,
45
+ startYear,
46
+ timeGranularity,
47
+ campaignId,
48
+ getListParam,
49
+ createReport,
50
+ } = this;
51
+
52
+ const response = await createReport({
53
+ $,
54
+ params: {
55
+ "q": "analytics",
56
+ "pivot": "CAMPAIGN",
57
+ "dateRange": getDateRangeParam(`${startYear}-01-01`),
58
+ timeGranularity,
59
+ "campaigns": getListParam([
60
+ app.getSponsoredCampaignUrn(campaignId),
61
+ ]),
62
+ },
63
+ });
64
+
65
+ $.export("$summary", "Successfully retrieved analytics");
66
+
67
+ return response;
68
+ },
69
+ };
@@ -0,0 +1,149 @@
1
+ import { createHash } from "crypto";
2
+ import app from "../../linkedin_ads.app.mjs";
3
+
4
+ export default {
5
+ key: "linkedin_ads-send-conversion-event",
6
+ name: "Send Conversion Event",
7
+ description: "Sends a conversion event to LinkedIn Ads. [See the documentation](https://learn.microsoft.com/en-us/linkedin/marketing/integrations/ads-reporting/conversions-api?view=li-lms-2024-01&tabs=http#streaming-conversion-events)",
8
+ version: "0.0.3",
9
+ type: "action",
10
+ props: {
11
+ app,
12
+ adAccountId: {
13
+ propDefinition: [
14
+ app,
15
+ "adAccountId",
16
+ ],
17
+ },
18
+ conversionId: {
19
+ propDefinition: [
20
+ app,
21
+ "conversionId",
22
+ ({ adAccountId }) => ({
23
+ adAccountId,
24
+ }),
25
+ ],
26
+ },
27
+ conversionHappenedAt: {
28
+ type: "string",
29
+ label: "Conversion Happened At",
30
+ description: "Epoch timestamp in milliseconds at which the conversion event happened. Note: If your source records conversion timestamp in seconds, please insert 000 at the end to transform it to milliseconds. Eg. `1590739275000`.",
31
+ },
32
+ email: {
33
+ type: "string",
34
+ label: "Email",
35
+ description: "Email address of the contact associated with the conversion event which needs to be in SHA256 format, a HEX encoded string with a maximum length of 64 characters. Eg. `test@example.com`.",
36
+ },
37
+ firstName: {
38
+ type: "string",
39
+ label: "First Name",
40
+ description: "The first name of the contact to match the conversion.",
41
+ },
42
+ lastName: {
43
+ type: "string",
44
+ label: "Last Name",
45
+ description: "The last name of the contact to match the conversion.",
46
+ },
47
+ conversionValueCurrencyCode: {
48
+ type: "string",
49
+ label: "Conversion Value Currency Code",
50
+ description: "The currency code of the conversion value in ISO format. Eg. `USD`.",
51
+ },
52
+ conversionValueAmount: {
53
+ type: "string",
54
+ label: "Conversion Value Amount",
55
+ description: "The value of the conversion in decimal string. If you set this field, you must also set in the **Conversion Value Currency Code** field. Eg. `100.05`.",
56
+ },
57
+ companyName: {
58
+ type: "string",
59
+ label: "Company Name",
60
+ description: "A plain text string representing the company of the contact to match.",
61
+ optional: true,
62
+ },
63
+ title: {
64
+ type: "string",
65
+ label: "Title",
66
+ description: "A plain text string representing the title name of the contact to match. Eg. `Software Engineer`.",
67
+ optional: true,
68
+ },
69
+ countryCode: {
70
+ type: "string",
71
+ label: "Country Code",
72
+ description: "An ISO standardized [two letter country code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) representing the country of the contact to match. Eg. `US`.",
73
+ optional: true,
74
+ },
75
+ eventId: {
76
+ type: "string",
77
+ label: "Event ID",
78
+ description: "The unique id generated by advertisers to indicate each event. This field is used for [deduplication](https://learn.microsoft.com/en-us/linkedin/marketing/conversions/deduplication?view=li-lms-2024-01).",
79
+ optional: true,
80
+ },
81
+ },
82
+ methods: {
83
+ emailToSha256(email) {
84
+ return createHash("sha256")
85
+ .update(email)
86
+ .digest("hex");
87
+ },
88
+ sendConversionEvent(args = {}) {
89
+ return this.app._makeRequest({
90
+ debug: true,
91
+ method: "POST",
92
+ path: "/conversionEvents",
93
+ ...args,
94
+ });
95
+ },
96
+ },
97
+ async run({ $ }) {
98
+ const {
99
+ app,
100
+ emailToSha256,
101
+ sendConversionEvent,
102
+ conversionId,
103
+ conversionHappenedAt,
104
+ conversionValueCurrencyCode,
105
+ conversionValueAmount,
106
+ email,
107
+ firstName,
108
+ lastName,
109
+ companyName,
110
+ title,
111
+ countryCode,
112
+ eventId,
113
+ } = this;
114
+
115
+ await sendConversionEvent({
116
+ $,
117
+ data: {
118
+ conversion: app.getConversionUrn(conversionId),
119
+ conversionHappenedAt: Number(conversionHappenedAt),
120
+ conversionValue: {
121
+ currencyCode: conversionValueCurrencyCode,
122
+ amount: conversionValueAmount,
123
+ },
124
+ user: {
125
+ userIds: [
126
+ {
127
+ idType: "SHA256_EMAIL",
128
+ idValue: emailToSha256(email),
129
+ },
130
+ ],
131
+ userInfo: {
132
+ firstName,
133
+ lastName,
134
+ companyName,
135
+ title,
136
+ countryCode,
137
+ },
138
+ },
139
+ eventId,
140
+ },
141
+ });
142
+
143
+ $.export("$summary", "Successfully sent conversion event to LinkedIn Ads");
144
+
145
+ return {
146
+ success: true,
147
+ };
148
+ },
149
+ };
@@ -0,0 +1,54 @@
1
+ function encodeParamKeys(keys = []) {
2
+ return (key, value) => {
3
+ if (!keys.includes(key)) {
4
+ return `${key}=${value}`;
5
+ }
6
+ const [
7
+ firstPart,
8
+ ...otherParts
9
+ ] = value.split(":");
10
+
11
+ if (!firstPart?.startsWith("(")) {
12
+ const encoded = encodeURIComponent(value)
13
+ .replace("(", "%28")
14
+ .replace(")", "%29");
15
+ return `${key}=${encoded}`;
16
+ }
17
+
18
+ return `${key}=${firstPart}:${encodeURIComponent(otherParts.join(":"))}`;
19
+ };
20
+ }
21
+
22
+ function defaultEncodeFn(key, value) {
23
+ return `${key}=${value}`;
24
+ }
25
+
26
+ function encodeFn(key, value) {
27
+ return `${key}=${encodeURIComponent(value)}`;
28
+ }
29
+
30
+ function getParamsSerializer(encodeFn = defaultEncodeFn) {
31
+ return (params) => {
32
+ return Object.entries(params)
33
+ .map(([
34
+ key,
35
+ value,
36
+ ]) => encodeFn(key, value))
37
+ .join("&");
38
+ };
39
+ }
40
+
41
+ function transformResponse(jsonStr) {
42
+ // Regex to target specifically "id" fields, capturing
43
+ // the number to convert it into a string
44
+ // Because the number can be a long number or big integer
45
+ const response = jsonStr.replace(/("id"\s*:\s*)(\d+)/g, "$1\"$2\"");
46
+ return JSON.parse(response);
47
+ }
48
+
49
+ export default {
50
+ encodeParamKeys,
51
+ encodeFn,
52
+ getParamsSerializer,
53
+ transformResponse,
54
+ };
@@ -123,6 +123,31 @@ export default {
123
123
  }));
124
124
  },
125
125
  },
126
+ leadFormId: {
127
+ type: "string",
128
+ label: "Lead Form ID",
129
+ description: "Select the lead form to retrieve responses for.",
130
+ async options({
131
+ page, adAccountId,
132
+ }) {
133
+ const count = 20;
134
+ const { elements } = await this.searchLeadForms({
135
+ params: {
136
+ q: "owner",
137
+ owner: `(sponsoredAccount:${this.getSponsoredAccountUrn(adAccountId)})`,
138
+ count,
139
+ start: page * count,
140
+ },
141
+ });
142
+ return elements.map(({
143
+ id,
144
+ name: label,
145
+ }) => ({
146
+ label,
147
+ value: String(id),
148
+ }));
149
+ },
150
+ },
126
151
  },
127
152
  methods: {
128
153
  ...app.methods,
@@ -141,6 +166,9 @@ export default {
141
166
  getEventUrn(id) {
142
167
  return `urn:li:event:${id}`;
143
168
  },
169
+ getVersionedLeadGenFormUrn(id, version = 1) {
170
+ return `urn:li:versionedLeadGenForm:(urn:li:leadGenForm:${id},${version})`;
171
+ },
144
172
  searchCampaigns({
145
173
  adAccountId, ...args
146
174
  } = {}) {
@@ -154,18 +182,24 @@ export default {
154
182
  "owner",
155
183
  ];
156
184
  return this._makeRequest({
157
- debug: true,
158
185
  path: "/leadForms",
159
186
  paramsSerializer: utils.getParamsSerializer(utils.encodeParamKeys(keys)),
160
187
  ...args,
161
188
  });
162
189
  },
190
+ getLeadForm({
191
+ leadFormId, ...args
192
+ } = {}) {
193
+ return this._makeRequest({
194
+ path: `/leadForms/${leadFormId}`,
195
+ ...args,
196
+ });
197
+ },
163
198
  searchEvents(args = {}) {
164
199
  const keys = [
165
200
  "organizer",
166
201
  ];
167
202
  return this._makeRequest({
168
- debug: true,
169
203
  path: "/events",
170
204
  paramsSerializer: utils.getParamsSerializer(utils.encodeParamKeys(keys)),
171
205
  transformResponse: utils.transformResponse,
@@ -174,7 +208,6 @@ export default {
174
208
  },
175
209
  searchConversions(args = {}) {
176
210
  return this._makeRequest({
177
- debug: true,
178
211
  path: "/conversions",
179
212
  paramsSerializer: utils.getParamsSerializer(utils.encodeFn),
180
213
  ...args,
@@ -187,7 +220,6 @@ export default {
187
220
  "associatedEntity",
188
221
  ];
189
222
  return this._makeRequest({
190
- debug: true,
191
223
  path: "/leadFormResponses",
192
224
  paramsSerializer: utils.getParamsSerializer(utils.encodeParamKeys(keys)),
193
225
  ...args,
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@pipedream/linkedin_ads",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Pipedream LinkedIn Ads Components",
5
5
  "main": "linkedin_ads.app.mjs",
6
6
  "keywords": [
7
7
  "pipedream",
8
8
  "linkedin_ads"
9
9
  ],
10
- "files": [
11
- "dist"
12
- ],
13
10
  "homepage": "https://pipedream.com/apps/linkedin_ads",
14
11
  "author": "Pipedream <support@pipedream.com> (https://pipedream.com/)",
15
12
  "publishConfig": {
16
13
  "access": "public"
14
+ },
15
+ "dependencies": {
16
+ "@pipedream/platform": "^3.0.3"
17
17
  }
18
18
  }
@@ -0,0 +1,62 @@
1
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
2
+ import app from "../../linkedin_ads.app.mjs";
3
+
4
+ export default {
5
+ key: "linkedin_ads-new-event-registration-form-response",
6
+ name: "New Event Registration Form Response",
7
+ description: "Emit new event when a fresh response is received on the event registration form. User needs to configure the prop of the specific event. [See the documentation](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/organizations/events?view=li-lms-2024-01&tabs=http)",
8
+ version: "0.0.3",
9
+ type: "source",
10
+ dedupe: "unique",
11
+ props: {
12
+ app,
13
+ timer: {
14
+ type: "$.interface.timer",
15
+ default: {
16
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
17
+ },
18
+ },
19
+ organizationId: {
20
+ propDefinition: [
21
+ app,
22
+ "organizationId",
23
+ ],
24
+ },
25
+ eventId: {
26
+ propDefinition: [
27
+ app,
28
+ "eventId",
29
+ ({ organizationId }) => ({
30
+ organizationId,
31
+ }),
32
+ ],
33
+ },
34
+ },
35
+ async run() {
36
+ const {
37
+ app,
38
+ organizationId,
39
+ eventId,
40
+ } = this;
41
+
42
+ const { elements } = await app.searchLeadFormResponses({
43
+ params: {
44
+ q: "owner",
45
+ owner: `(organization:${app.getOrganizationUrn(organizationId)})`,
46
+ leadType: "(leadType:EVENT)",
47
+ limitedToTestLeads: false,
48
+ associatedEntity: app.getEventUrn(eventId),
49
+ },
50
+ });
51
+
52
+ elements
53
+ .reverse()
54
+ .forEach((event) => {
55
+ this.$emit(event, {
56
+ id: event.id,
57
+ summary: `New Event Registration: ${event.id}`,
58
+ ts: event.submittedAt,
59
+ });
60
+ });
61
+ },
62
+ };
@@ -0,0 +1,68 @@
1
+ import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
2
+ import app from "../../linkedin_ads.app.mjs";
3
+ import sampleEmit from "./test-event.mjs";
4
+
5
+ export default {
6
+ key: "linkedin_ads-new-lead-gen-form-created",
7
+ name: "New Lead Gen Form Created",
8
+ description: "Emit new event when a new lead is captured through a form. [See the documentation](https://learn.microsoft.com/en-us/linkedin/marketing/lead-sync/leadsync?view=li-lms-2023-07&tabs=http#find-lead-form-responses-by-owner)",
9
+ version: "0.0.2",
10
+ type: "source",
11
+ dedupe: "unique",
12
+ props: {
13
+ app,
14
+ timer: {
15
+ type: "$.interface.timer",
16
+ default: {
17
+ intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
18
+ },
19
+ },
20
+ adAccountId: {
21
+ propDefinition: [
22
+ app,
23
+ "adAccountId",
24
+ ],
25
+ },
26
+ leadFormId: {
27
+ propDefinition: [
28
+ app,
29
+ "leadFormId",
30
+ ({ adAccountId }) => ({
31
+ adAccountId,
32
+ }),
33
+ ],
34
+ },
35
+ },
36
+ async run() {
37
+ const {
38
+ app,
39
+ adAccountId,
40
+ leadFormId,
41
+ } = this;
42
+
43
+ const { versionId: leadFormVersionId } = await app.getLeadForm({
44
+ leadFormId,
45
+ });
46
+
47
+ const { elements } = await app.searchLeadFormResponses({
48
+ params: {
49
+ q: "owner",
50
+ owner: `(sponsoredAccount:${app.getSponsoredAccountUrn(adAccountId)})`,
51
+ leadType: "(leadType:SPONSORED)",
52
+ limitedToTestLeads: false,
53
+ versionedLeadGenFormUrn: app.getVersionedLeadGenFormUrn(leadFormId, leadFormVersionId),
54
+ },
55
+ });
56
+
57
+ elements
58
+ .reverse()
59
+ .forEach((event) => {
60
+ this.$emit(event, {
61
+ id: event.id,
62
+ summary: `New Lead Gen: ${event.id}`,
63
+ ts: event.submittedAt,
64
+ });
65
+ });
66
+ },
67
+ sampleEmit,
68
+ };
@@ -0,0 +1,48 @@
1
+ export default {
2
+ "owner": {
3
+ "sponsoredAccount": "urn:li:sponsoredAccount:1232131"
4
+ },
5
+ "submitter": "urn:li:person:0",
6
+ "leadType": "SPONSORED",
7
+ "leadMetadata": {
8
+ "sponsoredLeadMetadata": {
9
+ "campaign": "urn:li:sponsoredCampaign:32131231"
10
+ }
11
+ },
12
+ "versionedLeadGenFormUrn": "urn:li:versionedLeadGenForm:(urn:li:leadGenForm:3213,1)",
13
+ "id": "52dcb737-26f9-4af3-b1fc-935b3e93f838-4",
14
+ "submittedAt": 1706741502694,
15
+ "testLead": true,
16
+ "associatedEntity": {
17
+ "associatedCreative": "urn:li:sponsoredCreative:369799186"
18
+ },
19
+ "formResponse": {
20
+ "consentResponses": [],
21
+ "answers": [
22
+ {
23
+ "answerDetails": {
24
+ "textQuestionAnswer": {
25
+ "answer": "test1@gmail.com"
26
+ }
27
+ },
28
+ "questionId": 20502584796
29
+ },
30
+ {
31
+ "answerDetails": {
32
+ "textQuestionAnswer": {
33
+ "answer": "Test 1"
34
+ }
35
+ },
36
+ "questionId": 20502643516
37
+ },
38
+ {
39
+ "answerDetails": {
40
+ "textQuestionAnswer": {
41
+ "answer": "Test 1"
42
+ }
43
+ },
44
+ "questionId": 20502667260
45
+ }
46
+ ]
47
+ }
48
+ };