@seranking/n8n-nodes-seranking 1.5.10 → 1.5.13

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.
@@ -1,5 +1,10 @@
1
- import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
1
+ import { IExecuteFunctions, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
2
  export declare class SeRanking implements INodeType {
3
3
  description: INodeTypeDescription;
4
+ methods: {
5
+ loadOptions: {
6
+ getAuditIssueCodes(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]>;
7
+ };
8
+ };
4
9
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
10
  }
@@ -11,6 +11,7 @@ const SerpClassicDescription_1 = require("./dataApi/descriptions/SerpClassicDesc
11
11
  const ProjectManagementDescription_1 = require("./projectApi/descriptions/ProjectManagementDescription");
12
12
  const ProjectGroupsDescription_1 = require("./projectApi/descriptions/ProjectGroupsDescription");
13
13
  const AiResultTrackerDescription_1 = require("./projectApi/descriptions/AiResultTrackerDescription");
14
+ const AirtGroupsDescription_1 = require("./projectApi/descriptions/AirtGroupsDescription");
14
15
  const KeywordGroupsDescription_1 = require("./projectApi/descriptions/KeywordGroupsDescription");
15
16
  const CompetitorsDescription_1 = require("./projectApi/descriptions/CompetitorsDescription");
16
17
  const UrlTagsDescription_1 = require("./projectApi/descriptions/UrlTagsDescription");
@@ -31,6 +32,7 @@ const SerpClassicOperations_1 = require("./dataApi/operations/SerpClassicOperati
31
32
  const ProjectManagementOperations_1 = require("./projectApi/operations/ProjectManagementOperations");
32
33
  const ProjectGroupsOperations_1 = require("./projectApi/operations/ProjectGroupsOperations");
33
34
  const AiResultTrackerOperations_1 = require("./projectApi/operations/AiResultTrackerOperations");
35
+ const AirtGroupsOperations_1 = require("./projectApi/operations/AirtGroupsOperations");
34
36
  const KeywordGroupsOperations_1 = require("./projectApi/operations/KeywordGroupsOperations");
35
37
  const CompetitorsOperations_1 = require("./projectApi/operations/CompetitorsOperations");
36
38
  const UrlTagsOperations_1 = require("./projectApi/operations/UrlTagsOperations");
@@ -83,6 +85,7 @@ class SeRanking {
83
85
  resource: [
84
86
  'accountSystem',
85
87
  'aiResultTracker',
88
+ 'airtGroups',
86
89
  'analyticsTraffic',
87
90
  'backlinkChecker',
88
91
  'competitors',
@@ -117,6 +120,11 @@ class SeRanking {
117
120
  value: 'aiResultTracker',
118
121
  description: 'Track brand visibility across AI search engines',
119
122
  },
123
+ {
124
+ name: 'AIRT Groups',
125
+ value: 'airtGroups',
126
+ description: 'Manage AI Result Tracker prompt groups',
127
+ },
120
128
  {
121
129
  name: 'AI Search',
122
130
  value: 'aiSearch',
@@ -228,6 +236,8 @@ class SeRanking {
228
236
  ...ProjectGroupsDescription_1.projectGroupsFields,
229
237
  ...AiResultTrackerDescription_1.aiResultTrackerOperations,
230
238
  ...AiResultTrackerDescription_1.aiResultTrackerFields,
239
+ ...AirtGroupsDescription_1.airtGroupsOperations,
240
+ ...AirtGroupsDescription_1.airtGroupsFields,
231
241
  ...KeywordGroupsDescription_1.keywordGroupsOperations,
232
242
  ...KeywordGroupsDescription_1.keywordGroupsFields,
233
243
  ...CompetitorsDescription_1.competitorsOperations,
@@ -252,6 +262,34 @@ class SeRanking {
252
262
  ...SearchVolumeDescription_1.searchVolumeFields,
253
263
  ],
254
264
  };
265
+ this.methods = {
266
+ loadOptions: {
267
+ async getAuditIssueCodes() {
268
+ const auditId = this.getCurrentNodeParameter('auditId');
269
+ if (!auditId) {
270
+ return [];
271
+ }
272
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'seRankingProjectApi', {
273
+ method: 'GET',
274
+ url: `https://api4.seranking.com/audit/${auditId}/report`,
275
+ json: true,
276
+ });
277
+ const codes = new Set();
278
+ const sections = (response && response.sections) || [];
279
+ for (const section of sections) {
280
+ const props = section && section.props;
281
+ if (props && typeof props === 'object') {
282
+ for (const key of Object.keys(props)) {
283
+ codes.add(key);
284
+ }
285
+ }
286
+ }
287
+ return Array.from(codes)
288
+ .sort()
289
+ .map((code) => ({ name: code, value: code }));
290
+ },
291
+ },
292
+ };
255
293
  }
256
294
  async execute() {
257
295
  const items = this.getInputData();
@@ -288,6 +326,9 @@ class SeRanking {
288
326
  case 'aiResultTracker':
289
327
  responseData = await AiResultTrackerOperations_1.AiResultTrackerOperations.call(this, i);
290
328
  break;
329
+ case 'airtGroups':
330
+ responseData = await AirtGroupsOperations_1.AirtGroupsOperations.call(this, i);
331
+ break;
291
332
  case 'keywordGroups':
292
333
  responseData = await KeywordGroupsOperations_1.KeywordGroupsOperations.call(this, i);
293
334
  break;
@@ -302,6 +302,14 @@ exports.aiResultTrackerFields = [
302
302
  },
303
303
  },
304
304
  options: [
305
+ {
306
+ displayName: 'Group IDs',
307
+ name: 'groupIds',
308
+ type: 'string',
309
+ default: '',
310
+ placeholder: '12,18',
311
+ description: 'Comma-separated prompt group IDs to filter by',
312
+ },
305
313
  {
306
314
  displayName: 'Limit',
307
315
  name: 'limit',
@@ -333,6 +341,28 @@ exports.aiResultTrackerFields = [
333
341
  placeholder: 'best seo tool,seo rank tracker,website audit tool',
334
342
  description: 'Comma-separated list of keyword prompts to add (max 255 chars each)',
335
343
  },
344
+ {
345
+ displayName: 'Additional Fields',
346
+ name: 'additionalFields',
347
+ type: 'collection',
348
+ placeholder: 'Add Field',
349
+ default: {},
350
+ displayOptions: {
351
+ show: {
352
+ resource: ['aiResultTracker'],
353
+ operation: ['addPrompts'],
354
+ },
355
+ },
356
+ options: [
357
+ {
358
+ displayName: 'Group ID',
359
+ name: 'groupId',
360
+ type: 'number',
361
+ default: 0,
362
+ description: 'Target prompt group ID. Defaults to the site\'s default group.',
363
+ },
364
+ ],
365
+ },
336
366
  {
337
367
  displayName: 'Keyword-LLM Link IDs',
338
368
  name: 'k2siteLlmIds',
@@ -377,6 +407,14 @@ exports.aiResultTrackerFields = [
377
407
  placeholder: '2026-01-31',
378
408
  description: 'End date (YYYY-MM-DD). Defaults to current date.',
379
409
  },
410
+ {
411
+ displayName: 'Group IDs',
412
+ name: 'groupIds',
413
+ type: 'string',
414
+ default: '',
415
+ placeholder: '12,18',
416
+ description: 'Comma-separated prompt group IDs to filter by',
417
+ },
380
418
  {
381
419
  displayName: 'Limit',
382
420
  name: 'limit',
@@ -405,7 +443,7 @@ exports.aiResultTrackerFields = [
405
443
  },
406
444
  },
407
445
  default: 0,
408
- description: 'Value of the <code>k2site_llm_id</code> field from List Prompts (the SE Ranking docs call this parameter <code>keyword_id</code>, but the endpoint actually expects <code>k2site_llm_id</code>)',
446
+ description: 'Value of the <code>k2site_llm_id</code> field from List Prompts',
409
447
  },
410
448
  {
411
449
  displayName: 'Additional Fields',
@@ -0,0 +1,3 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const airtGroupsOperations: INodeProperties[];
3
+ export declare const airtGroupsFields: INodeProperties[];
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.airtGroupsFields = exports.airtGroupsOperations = void 0;
4
+ exports.airtGroupsOperations = [
5
+ {
6
+ displayName: 'Operation',
7
+ name: 'operation',
8
+ type: 'options',
9
+ noDataExpression: true,
10
+ displayOptions: {
11
+ show: {
12
+ resource: ['airtGroups'],
13
+ },
14
+ },
15
+ options: [
16
+ {
17
+ name: 'Change Group Order',
18
+ value: 'changeGroupOrder',
19
+ description: 'Move a group to a new position in the site group order',
20
+ action: 'Change prompt group order',
21
+ },
22
+ {
23
+ name: 'Create Prompt Group',
24
+ value: 'createPromptGroup',
25
+ description: 'Create a new prompt group for a site',
26
+ action: 'Create prompt group',
27
+ },
28
+ {
29
+ name: 'Delete All Prompts in Group',
30
+ value: 'deleteAllPromptsInGroup',
31
+ description: 'Remove every prompt currently assigned to the group (group itself is kept)',
32
+ action: 'Delete all prompts in group',
33
+ },
34
+ {
35
+ name: 'Delete Prompt Group',
36
+ value: 'deletePromptGroup',
37
+ description: 'Delete a prompt group; its prompts move to the default group',
38
+ action: 'Delete prompt group',
39
+ },
40
+ {
41
+ name: 'List Prompt Groups',
42
+ value: 'listPromptGroups',
43
+ description: 'List prompt groups for a site, optionally filtered by LLM engine',
44
+ action: 'List prompt groups',
45
+ },
46
+ {
47
+ name: 'Move All Prompts Between Groups',
48
+ value: 'moveAllPromptsBetweenGroups',
49
+ description: 'Move every prompt from one group to another',
50
+ action: 'Move all prompts between groups',
51
+ },
52
+ {
53
+ name: 'Move Prompts to Group',
54
+ value: 'movePromptsToGroup',
55
+ description: 'Move a specific set of prompts into a target group',
56
+ action: 'Move prompts to group',
57
+ },
58
+ {
59
+ name: 'Rename Prompt Group',
60
+ value: 'renamePromptGroup',
61
+ description: 'Update the name of an existing prompt group',
62
+ action: 'Rename prompt group',
63
+ },
64
+ ],
65
+ default: 'listPromptGroups',
66
+ },
67
+ ];
68
+ exports.airtGroupsFields = [
69
+ {
70
+ displayName: 'Site ID',
71
+ name: 'siteId',
72
+ type: 'number',
73
+ required: true,
74
+ displayOptions: {
75
+ show: {
76
+ resource: ['airtGroups'],
77
+ },
78
+ },
79
+ default: 0,
80
+ description: 'Unique project (site) ID',
81
+ },
82
+ {
83
+ displayName: 'Group ID',
84
+ name: 'groupId',
85
+ type: 'number',
86
+ required: true,
87
+ displayOptions: {
88
+ show: {
89
+ resource: ['airtGroups'],
90
+ operation: [
91
+ 'renamePromptGroup',
92
+ 'deletePromptGroup',
93
+ 'changeGroupOrder',
94
+ 'deleteAllPromptsInGroup',
95
+ 'movePromptsToGroup',
96
+ ],
97
+ },
98
+ },
99
+ default: 0,
100
+ description: 'Prompt group ID',
101
+ },
102
+ {
103
+ displayName: 'Group Name',
104
+ name: 'groupName',
105
+ type: 'string',
106
+ required: true,
107
+ displayOptions: {
108
+ show: {
109
+ resource: ['airtGroups'],
110
+ operation: ['createPromptGroup'],
111
+ },
112
+ },
113
+ default: '',
114
+ placeholder: 'Brand queries',
115
+ description: 'Non-empty, max 255 characters, unique within the site',
116
+ },
117
+ {
118
+ displayName: 'New Group Name',
119
+ name: 'groupName',
120
+ type: 'string',
121
+ required: true,
122
+ displayOptions: {
123
+ show: {
124
+ resource: ['airtGroups'],
125
+ operation: ['renamePromptGroup'],
126
+ },
127
+ },
128
+ default: '',
129
+ placeholder: 'Updated group name',
130
+ description: 'New name for the prompt group; non-empty, max 255 characters',
131
+ },
132
+ {
133
+ displayName: 'Place Before Group ID',
134
+ name: 'beforeId',
135
+ type: 'number',
136
+ displayOptions: {
137
+ show: {
138
+ resource: ['airtGroups'],
139
+ operation: ['changeGroupOrder'],
140
+ },
141
+ },
142
+ default: 0,
143
+ description: 'Place the group immediately before this neighbour. Provide exactly ONE of Before or After — leave the other at 0',
144
+ },
145
+ {
146
+ displayName: 'Place After Group ID',
147
+ name: 'afterId',
148
+ type: 'number',
149
+ displayOptions: {
150
+ show: {
151
+ resource: ['airtGroups'],
152
+ operation: ['changeGroupOrder'],
153
+ },
154
+ },
155
+ default: 0,
156
+ description: 'Place the group immediately after this neighbour. Provide exactly ONE of Before or After — leave the other at 0',
157
+ },
158
+ {
159
+ displayName: 'Keyword-LLM Link IDs',
160
+ name: 'k2siteLlmIds',
161
+ type: 'string',
162
+ required: true,
163
+ displayOptions: {
164
+ show: {
165
+ resource: ['airtGroups'],
166
+ operation: ['movePromptsToGroup'],
167
+ },
168
+ },
169
+ default: '',
170
+ placeholder: '2164555,2164556,2164557',
171
+ description: 'Comma-separated list of integer k2site_llm_id values (from List Prompts)',
172
+ },
173
+ {
174
+ displayName: 'Source Group ID',
175
+ name: 'fromGroupId',
176
+ type: 'number',
177
+ required: true,
178
+ displayOptions: {
179
+ show: {
180
+ resource: ['airtGroups'],
181
+ operation: ['moveAllPromptsBetweenGroups'],
182
+ },
183
+ },
184
+ default: 0,
185
+ description: 'Group whose prompts will be moved',
186
+ },
187
+ {
188
+ displayName: 'Target Group ID',
189
+ name: 'toGroupId',
190
+ type: 'number',
191
+ required: true,
192
+ displayOptions: {
193
+ show: {
194
+ resource: ['airtGroups'],
195
+ operation: ['moveAllPromptsBetweenGroups'],
196
+ },
197
+ },
198
+ default: 0,
199
+ description: 'Destination group; must differ from Source Group ID',
200
+ },
201
+ {
202
+ displayName: 'Additional Fields',
203
+ name: 'additionalFields',
204
+ type: 'collection',
205
+ placeholder: 'Add Field',
206
+ default: {},
207
+ displayOptions: {
208
+ show: {
209
+ resource: ['airtGroups'],
210
+ operation: ['listPromptGroups'],
211
+ },
212
+ },
213
+ options: [
214
+ {
215
+ displayName: 'Include Prompt Counts',
216
+ name: 'keysCount',
217
+ type: 'boolean',
218
+ default: false,
219
+ description: 'Whether to include keys_count on every group',
220
+ },
221
+ {
222
+ displayName: 'Filter by Site LLM IDs',
223
+ name: 'siteLlmIds',
224
+ type: 'string',
225
+ default: '',
226
+ placeholder: '1130467,1130468',
227
+ description: 'Comma-separated list of site_llm_id values to filter groups by',
228
+ },
229
+ ],
230
+ },
231
+ ];
@@ -230,10 +230,14 @@ exports.websiteAuditFields = [
230
230
  ],
231
231
  },
232
232
  {
233
- displayName: 'Issue Code',
233
+ displayName: 'Issue Code Name or ID',
234
234
  name: 'issueCode',
235
- type: 'string',
235
+ type: 'options',
236
236
  required: true,
237
+ typeOptions: {
238
+ loadOptionsMethod: 'getAuditIssueCodes',
239
+ loadOptionsDependsOn: ['auditId'],
240
+ },
237
241
  displayOptions: {
238
242
  show: {
239
243
  resource: ['websiteAuditProject'],
@@ -241,8 +245,7 @@ exports.websiteAuditFields = [
241
245
  },
242
246
  },
243
247
  default: '',
244
- placeholder: 'title_duplicate',
245
- description: 'Unique issue code',
248
+ description: 'Issue code from the audit report. Set the Audit ID first; the dropdown will populate from the audit\'s issue codes. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>',
246
249
  },
247
250
  {
248
251
  displayName: 'Additional Fields',
@@ -79,13 +79,22 @@ async function AiResultTrackerOperations(index) {
79
79
  query.limit = additionalFields.limit;
80
80
  if (additionalFields.offset !== undefined)
81
81
  query.offset = additionalFields.offset;
82
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/llm/${llmId}/prompts`, {}, query, index);
82
+ let endpoint = `/sites/${siteId}/airt/llm/${llmId}/prompts`;
83
+ if (additionalFields.groupIds) {
84
+ const ids = additionalFields.groupIds.split(',').map((id) => id.trim());
85
+ endpoint += '?' + ids.map((id) => `group_ids[]=${encodeURIComponent(id)}`).join('&');
86
+ }
87
+ return await apiRequest_1.apiRequest.call(this, 'GET', endpoint, {}, query, index);
83
88
  }
84
89
  case 'addPrompts': {
85
90
  const llmId = this.getNodeParameter('llmId', index);
86
91
  const promptsStr = this.getNodeParameter('prompts', index);
87
92
  const prompts = promptsStr.split(',').map((p) => p.trim()).filter((p) => p.length > 0);
88
- return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/llm/${llmId}/prompts`, { prompts }, {}, index);
93
+ const additionalFields = this.getNodeParameter('additionalFields', index, {});
94
+ const body = { prompts };
95
+ if (additionalFields.groupId)
96
+ body.group_id = additionalFields.groupId;
97
+ return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/llm/${llmId}/prompts`, body, {}, index);
89
98
  }
90
99
  case 'deletePrompts': {
91
100
  const llmId = this.getNodeParameter('llmId', index);
@@ -106,7 +115,12 @@ async function AiResultTrackerOperations(index) {
106
115
  query.limit = additionalFields.limit;
107
116
  if (additionalFields.offset !== undefined)
108
117
  query.offset = additionalFields.offset;
109
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/llm/${llmId}/prompts/rankings`, {}, query, index);
118
+ let endpoint = `/sites/${siteId}/airt/llm/${llmId}/prompts/rankings`;
119
+ if (additionalFields.groupIds) {
120
+ const ids = additionalFields.groupIds.split(',').map((id) => id.trim());
121
+ endpoint += '?' + ids.map((id) => `group_ids[]=${encodeURIComponent(id)}`).join('&');
122
+ }
123
+ return await apiRequest_1.apiRequest.call(this, 'GET', endpoint, {}, query, index);
110
124
  }
111
125
  case 'getPromptAnswer': {
112
126
  const llmId = this.getNodeParameter('llmId', index);
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ export declare function AirtGroupsOperations(this: IExecuteFunctions, index: number): Promise<any>;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AirtGroupsOperations = AirtGroupsOperations;
4
+ const apiRequest_1 = require("../../utils/apiRequest");
5
+ async function AirtGroupsOperations(index) {
6
+ const operation = this.getNodeParameter('operation', index);
7
+ const siteId = this.getNodeParameter('siteId', index);
8
+ switch (operation) {
9
+ case 'listPromptGroups': {
10
+ const additionalFields = this.getNodeParameter('additionalFields', index, {});
11
+ const query = {};
12
+ if (additionalFields.keysCount === true) {
13
+ query.keys_count = 1;
14
+ }
15
+ if (additionalFields.siteLlmIds) {
16
+ const ids = additionalFields.siteLlmIds
17
+ .split(',')
18
+ .map((s) => parseInt(s.trim(), 10))
19
+ .filter((n) => !Number.isNaN(n));
20
+ if (ids.length > 0) {
21
+ query['site_llm_ids[]'] = ids;
22
+ }
23
+ }
24
+ return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/prompt-groups`, {}, query, index);
25
+ }
26
+ case 'createPromptGroup': {
27
+ const name = this.getNodeParameter('groupName', index);
28
+ if (!name || name.trim() === '') {
29
+ throw new Error('Group name cannot be empty');
30
+ }
31
+ return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups`, { name: name.trim() }, {}, index);
32
+ }
33
+ case 'renamePromptGroup': {
34
+ const groupId = this.getNodeParameter('groupId', index);
35
+ const name = this.getNodeParameter('groupName', index);
36
+ if (!name || name.trim() === '') {
37
+ throw new Error('Group name cannot be empty');
38
+ }
39
+ return await apiRequest_1.apiRequest.call(this, 'PATCH', `/sites/${siteId}/airt/prompt-groups/${groupId}`, { name: name.trim() }, {}, index);
40
+ }
41
+ case 'deletePromptGroup': {
42
+ const groupId = this.getNodeParameter('groupId', index);
43
+ await apiRequest_1.apiRequest.call(this, 'DELETE', `/sites/${siteId}/airt/prompt-groups/${groupId}`, {}, {}, index);
44
+ return { success: true, deleted: true, group_id: groupId };
45
+ }
46
+ case 'changeGroupOrder': {
47
+ const groupId = this.getNodeParameter('groupId', index);
48
+ const beforeId = this.getNodeParameter('beforeId', index, 0);
49
+ const afterId = this.getNodeParameter('afterId', index, 0);
50
+ const hasBefore = beforeId > 0;
51
+ const hasAfter = afterId > 0;
52
+ if (hasBefore === hasAfter) {
53
+ throw new Error('Provide exactly one of "Place Before Group ID" or "Place After Group ID" (not both, not neither)');
54
+ }
55
+ const body = {};
56
+ if (hasBefore)
57
+ body.before_id = beforeId;
58
+ if (hasAfter)
59
+ body.after_id = afterId;
60
+ await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups/${groupId}/order`, body, {}, index);
61
+ return { success: true, group_id: groupId, ...body };
62
+ }
63
+ case 'deleteAllPromptsInGroup': {
64
+ const groupId = this.getNodeParameter('groupId', index);
65
+ await apiRequest_1.apiRequest.call(this, 'DELETE', `/sites/${siteId}/airt/prompt-groups/${groupId}/keywords`, {}, {}, index);
66
+ return { success: true, emptied: true, group_id: groupId };
67
+ }
68
+ case 'movePromptsToGroup': {
69
+ const groupId = this.getNodeParameter('groupId', index);
70
+ const idsStr = this.getNodeParameter('k2siteLlmIds', index);
71
+ const ids = idsStr
72
+ .split(',')
73
+ .map((s) => parseInt(s.trim(), 10))
74
+ .filter((n) => !Number.isNaN(n));
75
+ if (ids.length === 0) {
76
+ throw new Error('Provide at least one k2site_llm_id');
77
+ }
78
+ await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups/${groupId}/moveKeywords`, { k2site_llm_ids: ids }, {}, index);
79
+ return { success: true, group_id: groupId, moved: ids };
80
+ }
81
+ case 'moveAllPromptsBetweenGroups': {
82
+ const fromGroupId = this.getNodeParameter('fromGroupId', index);
83
+ const toGroupId = this.getNodeParameter('toGroupId', index);
84
+ if (fromGroupId === toGroupId) {
85
+ throw new Error('Source and Target Group ID must differ');
86
+ }
87
+ await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups/moveGroupKeywords`, { from_group_id: fromGroupId, to_group_id: toGroupId }, {}, index);
88
+ return { success: true, from_group_id: fromGroupId, to_group_id: toGroupId };
89
+ }
90
+ default:
91
+ throw new Error(`Unknown AIRT Groups operation: ${operation}`);
92
+ }
93
+ }
@@ -220,7 +220,7 @@ async function ProjectManagementOperations(index) {
220
220
  const keywordsJson = this.getNodeParameter('recheckKeywords', index);
221
221
  body.keywords = typeof keywordsJson === 'string' ? JSON.parse(keywordsJson) : keywordsJson;
222
222
  }
223
- return await apiRequest_1.apiRequest.call(this, 'POST', `/api/sites/${siteId}/recheck`, body, {}, index);
223
+ return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/recheck`, body, {}, index);
224
224
  }
225
225
  default:
226
226
  throw new Error(`Unknown Project Management operation: ${operation}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seranking/n8n-nodes-seranking",
3
- "version": "1.5.10",
3
+ "version": "1.5.13",
4
4
  "description": "n8n connector for SE Ranking API - AI Search, Backlinks, Domain Analysis, Keyword Research, Website Audit, Project Management, Project Groups, AI Result Tracker, Keyword Groups, Competitors, URL Tags, Analytics Traffic, Account System, Sub-Account Management, General Data, Marketing Plan, Backlink Checker, Search Volume",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/seranking/n8n-nodes-seranking",