@seranking/n8n-nodes-seranking 1.5.13 → 2.0.0

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.
Files changed (25) hide show
  1. package/README.md +17 -10
  2. package/dist/credentials/SeRankingApi.credentials.js +2 -2
  3. package/dist/nodes/SeRanking/SeRanking.node.js +3 -39
  4. package/dist/nodes/SeRanking/projectApi/descriptions/AiResultTrackerDescription.js +11 -0
  5. package/dist/nodes/SeRanking/projectApi/descriptions/ProjectManagementDescription.js +127 -0
  6. package/dist/nodes/SeRanking/projectApi/descriptions/WebsiteAuditDescription.js +107 -1
  7. package/dist/nodes/SeRanking/projectApi/operations/AccountSystemOperations.js +2 -2
  8. package/dist/nodes/SeRanking/projectApi/operations/AiResultTrackerOperations.js +20 -18
  9. package/dist/nodes/SeRanking/projectApi/operations/AirtGroupsOperations.js +9 -9
  10. package/dist/nodes/SeRanking/projectApi/operations/AnalyticsTrafficOperations.js +3 -3
  11. package/dist/nodes/SeRanking/projectApi/operations/BacklinkCheckerOperations.js +19 -20
  12. package/dist/nodes/SeRanking/projectApi/operations/CompetitorsOperations.js +11 -8
  13. package/dist/nodes/SeRanking/projectApi/operations/GeneralDataOperations.js +7 -8
  14. package/dist/nodes/SeRanking/projectApi/operations/KeywordGroupsOperations.js +6 -6
  15. package/dist/nodes/SeRanking/projectApi/operations/MarketingPlanOperations.js +5 -5
  16. package/dist/nodes/SeRanking/projectApi/operations/ProjectGroupsOperations.js +6 -6
  17. package/dist/nodes/SeRanking/projectApi/operations/ProjectManagementOperations.js +70 -32
  18. package/dist/nodes/SeRanking/projectApi/operations/SearchVolumeOperations.js +5 -22
  19. package/dist/nodes/SeRanking/projectApi/operations/SubAccountOperations.js +8 -8
  20. package/dist/nodes/SeRanking/projectApi/operations/UrlTagsOperations.js +4 -4
  21. package/dist/nodes/SeRanking/projectApi/operations/WebsiteAuditOperations.js +57 -16
  22. package/dist/nodes/SeRanking/utils/apiRequest.js +6 -30
  23. package/package.json +3 -4
  24. package/dist/credentials/SeRankingProjectApi.credentials.d.ts +0 -9
  25. package/dist/credentials/SeRankingProjectApi.credentials.js +0 -39
package/README.md CHANGED
@@ -89,9 +89,10 @@ Open `http://localhost:5678` and add the SE Ranking node to your workflow.
89
89
  ### Step 4: Configure Credentials
90
90
 
91
91
  1. Add SE Ranking node
92
- 2. Click "Create New Credential" for **SE Ranking API** (Data API) — enter your Data API token
93
- 3. (Optional) Click "Create New Credential" for **SE Ranking Project API** — enter your Project API token
94
- 4. Save
92
+ 2. Click "Create New Credential" for **SE Ranking API** — enter your API token
93
+ 3. Save
94
+
95
+ > **v2.0.0 note:** SE Ranking unified its two APIs (Data API + Project API) onto a single host (`api.seranking.com`) with a single token in 2026-05. The node now uses one credential type for everything. If you're upgrading from v1.x, see the Migration section below.
95
96
 
96
97
  ### Docker Installation
97
98
 
@@ -156,19 +157,25 @@ Then restart n8n
156
157
 
157
158
  To use this node, you need:
158
159
 
159
- 1. **SE Ranking Account** - Sign up at [seranking.com](https://seranking.com/)
160
- 2. **API Token** - Generate from your [SE Ranking API Dashboard](https://online.seranking.com/admin.api.dashboard.html)
160
+ 1. **SE Ranking Account** Sign up at [seranking.com](https://seranking.com/)
161
+ 2. **API Token** Generate from your [SE Ranking API Dashboard](https://online.seranking.com/admin.api.dashboard.html)
161
162
 
162
163
  ### Setting up credentials in n8n
163
164
 
164
165
  1. Open any workflow and add the **SE Ranking** node
165
- 2. In the **SE Ranking API** credential slot, click "Create New Credential" and enter your **Data API token** — required for all Data API resources
166
- 3. In the **SE Ranking Project API** credential slot, click "Create New Credential" and enter your **Project API token** — only needed for Project API resources
167
- 4. Click **Save**
166
+ 2. In the **SE Ranking API** credential slot, click "Create New Credential" and enter your API token
167
+ 3. Click **Save** the credential is tested by hitting `GET /v1/account/subscription`
168
+
169
+ ### Migrating from v1.x
170
+
171
+ v1.x used two separate credential types (`seRankingApi` for Data API and `seRankingProjectApi` for Project API) with two different base URLs and two different tokens. As of v2.0.0:
168
172
 
169
- Each credential is tested independently when saved. The node automatically routes requests to the correct API and credential based on the resource you select.
173
+ - One credential type covers everything: **SE Ranking API**
174
+ - One token works against all endpoints — get the unified token from the [API Dashboard](https://online.seranking.com/admin.api.dashboard.html)
175
+ - Old base URL `api4.seranking.com` is deprecated; everything now lives under `api.seranking.com/v1`
176
+ - Project API endpoints moved under `/v1/project-management/...` path prefix
170
177
 
171
- > **Note:** Data API and Project API use different tokens. Data API tokens are UUID format; Project API tokens are 40-character hex format. Get both from your [SE Ranking API Dashboard](https://online.seranking.com/admin.api.dashboard.html).
178
+ If you're upgrading and have saved credentials of type `seRankingProjectApi`, you'll need to re-save them as `seRankingApi` on each affected node. The v1.5.13 release is preserved on npm for rollback (`npm install @seranking/n8n-nodes-seranking@1.5.13`).
172
179
 
173
180
  ---
174
181
 
@@ -5,7 +5,7 @@ class SeRankingApi {
5
5
  constructor() {
6
6
  this.name = 'seRankingApi';
7
7
  this.displayName = 'SE Ranking API';
8
- this.documentationUrl = 'https://seranking.com/api-google-organic.html';
8
+ this.documentationUrl = 'https://seranking.com/api/';
9
9
  this.properties = [
10
10
  {
11
11
  displayName: 'API Token',
@@ -16,7 +16,7 @@ class SeRankingApi {
16
16
  },
17
17
  default: '',
18
18
  required: true,
19
- description: 'Your SE Ranking Data API token from the API Dashboard',
19
+ description: 'Your SE Ranking API token from the API Dashboard. As of 2026-05 a single unified token authenticates both Data API and Project API endpoints.',
20
20
  },
21
21
  ];
22
22
  this.authenticate = {
@@ -64,43 +64,6 @@ class SeRanking {
64
64
  {
65
65
  name: 'seRankingApi',
66
66
  required: true,
67
- displayOptions: {
68
- show: {
69
- resource: [
70
- 'aiSearch',
71
- 'backlinks',
72
- 'domainAnalysis',
73
- 'keywordResearch',
74
- 'serpClassic',
75
- 'websiteAudit',
76
- ],
77
- },
78
- },
79
- },
80
- {
81
- name: 'seRankingProjectApi',
82
- required: true,
83
- displayOptions: {
84
- show: {
85
- resource: [
86
- 'accountSystem',
87
- 'aiResultTracker',
88
- 'airtGroups',
89
- 'analyticsTraffic',
90
- 'backlinkChecker',
91
- 'competitors',
92
- 'generalData',
93
- 'keywordGroups',
94
- 'marketingPlan',
95
- 'projectGroups',
96
- 'projectManagement',
97
- 'searchVolume',
98
- 'subAccount',
99
- 'urlTags',
100
- 'websiteAuditProject',
101
- ],
102
- },
103
- },
104
67
  },
105
68
  ],
106
69
  properties: [
@@ -269,9 +232,10 @@ class SeRanking {
269
232
  if (!auditId) {
270
233
  return [];
271
234
  }
272
- const response = await this.helpers.httpRequestWithAuthentication.call(this, 'seRankingProjectApi', {
235
+ const response = await this.helpers.httpRequestWithAuthentication.call(this, 'seRankingApi', {
273
236
  method: 'GET',
274
- url: `https://api4.seranking.com/audit/${auditId}/report`,
237
+ url: 'https://api.seranking.com/v1/project-management/audits/report',
238
+ qs: { audit_id: auditId },
275
239
  json: true,
276
240
  });
277
241
  const codes = new Set();
@@ -429,6 +429,17 @@ exports.aiResultTrackerFields = [
429
429
  default: 0,
430
430
  description: 'Offset from the beginning of the list',
431
431
  },
432
+ {
433
+ displayName: 'Mode',
434
+ name: 'mode',
435
+ type: 'options',
436
+ options: [
437
+ { name: 'Per Prompt (Default)', value: '' },
438
+ { name: 'Aggregated by Group', value: 'groups' },
439
+ ],
440
+ default: '',
441
+ description: 'Set to "groups" to get aggregated time-series per prompt group (mention_presence/link_presence as percentages) instead of per-prompt rankings',
442
+ },
432
443
  ],
433
444
  },
434
445
  {
@@ -187,6 +187,18 @@ exports.projectManagementOperations = [
187
187
  description: 'Set a ranking position for a keyword on a date',
188
188
  action: 'Set manual keyword position',
189
189
  },
190
+ {
191
+ name: 'List Check Dates',
192
+ value: 'listCheckDates',
193
+ description: 'Get actual ranking check dates for a project',
194
+ action: 'List check dates',
195
+ },
196
+ {
197
+ name: 'Get Ranking Trends',
198
+ value: 'getRankingTrends',
199
+ description: 'Get ranking trend time series (avg position, visibility, top10)',
200
+ action: 'Get ranking trends',
201
+ },
190
202
  ],
191
203
  default: 'listProjects',
192
204
  },
@@ -216,6 +228,8 @@ exports.projectManagementFields = [
216
228
  'deleteKeywords',
217
229
  'setManualPosition',
218
230
  'runRecheck',
231
+ 'listCheckDates',
232
+ 'getRankingTrends',
219
233
  ],
220
234
  },
221
235
  },
@@ -807,4 +821,117 @@ exports.projectManagementFields = [
807
821
  default: '[{"site_engine_id":1,"keyword_id":2}]',
808
822
  description: 'JSON array of objects: { site_engine_id, keyword_id }',
809
823
  },
824
+ {
825
+ displayName: 'Additional Fields',
826
+ name: 'additionalFields',
827
+ type: 'collection',
828
+ placeholder: 'Add Field',
829
+ default: {},
830
+ displayOptions: {
831
+ show: {
832
+ resource: ['projectManagement'],
833
+ operation: ['listCheckDates'],
834
+ },
835
+ },
836
+ options: [
837
+ {
838
+ displayName: 'Site Engine ID',
839
+ name: 'siteEngineId',
840
+ type: 'number',
841
+ default: 0,
842
+ description: 'Limit to a single search engine',
843
+ },
844
+ {
845
+ displayName: 'Date From',
846
+ name: 'dateFrom',
847
+ type: 'string',
848
+ default: '',
849
+ placeholder: '2026-01-01',
850
+ description: 'Start date (YYYY-MM-DD). Defaults to 7 days ago.',
851
+ },
852
+ {
853
+ displayName: 'Date To',
854
+ name: 'dateTo',
855
+ type: 'string',
856
+ default: '',
857
+ placeholder: '2026-01-31',
858
+ description: 'End date (YYYY-MM-DD). Defaults to today.',
859
+ },
860
+ ],
861
+ },
862
+ {
863
+ displayName: 'Additional Fields',
864
+ name: 'additionalFields',
865
+ type: 'collection',
866
+ placeholder: 'Add Field',
867
+ default: {},
868
+ displayOptions: {
869
+ show: {
870
+ resource: ['projectManagement'],
871
+ operation: ['getRankingTrends'],
872
+ },
873
+ },
874
+ options: [
875
+ {
876
+ displayName: 'Site Engine ID',
877
+ name: 'siteEngineId',
878
+ type: 'number',
879
+ default: 0,
880
+ description: 'Limit to a single search engine (drops the cross-engine average row)',
881
+ },
882
+ {
883
+ displayName: 'Date From',
884
+ name: 'dateFrom',
885
+ type: 'string',
886
+ default: '',
887
+ placeholder: '2026-01-01',
888
+ description: 'Start date (YYYY-MM-DD). Defaults to 7 days ago.',
889
+ },
890
+ {
891
+ displayName: 'Date To',
892
+ name: 'dateTo',
893
+ type: 'string',
894
+ default: '',
895
+ placeholder: '2026-01-31',
896
+ description: 'End date (YYYY-MM-DD). Defaults to today.',
897
+ },
898
+ {
899
+ displayName: 'Metric Type',
900
+ name: 'metricType',
901
+ type: 'options',
902
+ options: [
903
+ { name: 'Average Position', value: 'avg_pos' },
904
+ { name: 'Visibility (Raw Score)', value: 'visibility' },
905
+ { name: 'Visibility (%)', value: 'visibility_percent' },
906
+ { name: 'Top 10 (Count)', value: 'top10' },
907
+ { name: 'Top 10 (%)', value: 'top10_percent' },
908
+ ],
909
+ default: 'avg_pos',
910
+ description: 'Which ranking metric to retrieve',
911
+ },
912
+ {
913
+ displayName: 'Group ID',
914
+ name: 'groupId',
915
+ type: 'number',
916
+ default: 0,
917
+ description: 'Filter to a keyword group',
918
+ },
919
+ {
920
+ displayName: 'Keyword IDs',
921
+ name: 'keywordsIds',
922
+ type: 'string',
923
+ default: '',
924
+ placeholder: '123,456,789',
925
+ description: 'Comma-separated keyword IDs to filter',
926
+ },
927
+ {
928
+ displayName: 'Tag IDs',
929
+ name: 'tagsIds',
930
+ type: 'string',
931
+ default: '',
932
+ placeholder: '1,2,3',
933
+ description: 'Comma-separated landing-page tag IDs to filter',
934
+ },
935
+ ],
936
+ },
810
937
  ];
@@ -85,6 +85,54 @@ exports.websiteAuditOperations = [
85
85
  description: 'Update the title of an audit',
86
86
  action: 'Update audit title',
87
87
  },
88
+ {
89
+ name: 'Get Audit Settings',
90
+ value: 'getAuditSettings',
91
+ description: 'Get the full configuration of an audit',
92
+ action: 'Get audit settings',
93
+ },
94
+ {
95
+ name: 'Update Audit Settings',
96
+ value: 'updateAuditSettings',
97
+ description: 'Partially update audit configuration',
98
+ action: 'Update audit settings',
99
+ },
100
+ {
101
+ name: 'Reset Audit Settings',
102
+ value: 'resetAuditSettings',
103
+ description: 'Restore all audit settings to defaults',
104
+ action: 'Reset audit settings',
105
+ },
106
+ {
107
+ name: 'List Audit Sitemaps',
108
+ value: 'listAuditSitemaps',
109
+ description: 'List configured sitemaps for an audit',
110
+ action: 'List audit sitemaps',
111
+ },
112
+ {
113
+ name: 'Add Audit Sitemap',
114
+ value: 'addAuditSitemap',
115
+ description: 'Register a sitemap URL as a crawl source',
116
+ action: 'Add audit sitemap',
117
+ },
118
+ {
119
+ name: 'Delete Audit Sitemap',
120
+ value: 'deleteAuditSitemap',
121
+ description: 'Remove a sitemap from crawl sources',
122
+ action: 'Delete audit sitemap',
123
+ },
124
+ {
125
+ name: 'List Audit Source Pages',
126
+ value: 'listAuditSourcePages',
127
+ description: 'List uploaded custom page lists',
128
+ action: 'List audit source pages',
129
+ },
130
+ {
131
+ name: 'Delete Audit Source Pages',
132
+ value: 'deleteAuditSourcePages',
133
+ description: 'Remove an uploaded custom page list',
134
+ action: 'Delete audit source pages',
135
+ },
88
136
  ],
89
137
  default: 'listAudits',
90
138
  },
@@ -98,7 +146,7 @@ exports.websiteAuditFields = [
98
146
  displayOptions: {
99
147
  show: {
100
148
  resource: ['websiteAuditProject'],
101
- operation: ['getStatus', 'getReport', 'getPages', 'getPagesByIssue', 'getIssues', 'getLinks', 'getHistory', 'updateTitle', 'deleteAudit', 'recheckAudit'],
149
+ operation: ['getStatus', 'getReport', 'getPages', 'getPagesByIssue', 'getIssues', 'getLinks', 'getHistory', 'updateTitle', 'deleteAudit', 'recheckAudit', 'getAuditSettings', 'updateAuditSettings', 'resetAuditSettings', 'listAuditSitemaps', 'addAuditSitemap', 'deleteAuditSitemap', 'listAuditSourcePages', 'deleteAuditSourcePages'],
102
150
  },
103
151
  },
104
152
  default: 0,
@@ -379,4 +427,62 @@ exports.websiteAuditFields = [
379
427
  default: '',
380
428
  description: 'New title for the audit report (max 300 characters)',
381
429
  },
430
+ {
431
+ displayName: 'Settings JSON',
432
+ name: 'settingsJson',
433
+ type: 'string',
434
+ typeOptions: { rows: 5 },
435
+ required: true,
436
+ displayOptions: {
437
+ show: {
438
+ resource: ['websiteAuditProject'],
439
+ operation: ['updateAuditSettings'],
440
+ },
441
+ },
442
+ default: '{}',
443
+ description: 'JSON object of settings to update (partial update — only send changed fields). E.g. {"max_pages": 5000, "schedule_type": "week"}',
444
+ },
445
+ {
446
+ displayName: 'Sitemap URL',
447
+ name: 'sitemapUrl',
448
+ type: 'string',
449
+ required: true,
450
+ displayOptions: {
451
+ show: {
452
+ resource: ['websiteAuditProject'],
453
+ operation: ['addAuditSitemap'],
454
+ },
455
+ },
456
+ default: '',
457
+ placeholder: 'https://example.com/sitemap.xml',
458
+ description: 'Absolute URL of the sitemap to register as a crawl source',
459
+ },
460
+ {
461
+ displayName: 'Sitemap ID',
462
+ name: 'sitemapId',
463
+ type: 'number',
464
+ required: true,
465
+ displayOptions: {
466
+ show: {
467
+ resource: ['websiteAuditProject'],
468
+ operation: ['deleteAuditSitemap'],
469
+ },
470
+ },
471
+ default: 0,
472
+ description: 'ID of the sitemap to remove (from List Audit Sitemaps)',
473
+ },
474
+ {
475
+ displayName: 'Source Pages List ID',
476
+ name: 'sourcePagesListId',
477
+ type: 'string',
478
+ required: true,
479
+ displayOptions: {
480
+ show: {
481
+ resource: ['websiteAuditProject'],
482
+ operation: ['deleteAuditSourcePages'],
483
+ },
484
+ },
485
+ default: '',
486
+ description: 'ID of the uploaded page list to remove (from List Audit Source Pages)',
487
+ },
382
488
  ];
@@ -6,10 +6,10 @@ async function AccountSystemOperations(index) {
6
6
  const operation = this.getNodeParameter('operation', index);
7
7
  switch (operation) {
8
8
  case 'getBalance': {
9
- return await apiRequest_1.apiRequest.call(this, 'GET', '/account/balance', {}, {}, index);
9
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/account/subscription', {}, {}, index);
10
10
  }
11
11
  case 'getProfile': {
12
- return await apiRequest_1.apiRequest.call(this, 'GET', '/account/profile', {}, {}, index);
12
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/users/me', {}, {}, index);
13
13
  }
14
14
  case 'getSubscription': {
15
15
  return await apiRequest_1.apiRequest.call(this, 'GET', '/account/subscription', {}, {}, index);
@@ -7,7 +7,7 @@ async function AiResultTrackerOperations(index) {
7
7
  const siteId = this.getNodeParameter('siteId', index);
8
8
  switch (operation) {
9
9
  case 'getSiteBrand': {
10
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/brands`, {}, {}, index);
10
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/airt/brand', {}, { site_id: siteId }, index);
11
11
  }
12
12
  case 'saveSiteBrand': {
13
13
  const brand = this.getNodeParameter('brandName', index);
@@ -17,14 +17,14 @@ async function AiResultTrackerOperations(index) {
17
17
  if (brand.trim().length > 255) {
18
18
  throw new Error('Brand name cannot exceed 255 characters');
19
19
  }
20
- return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/brands`, { brand: brand.trim() }, {}, index);
20
+ return await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/brand', { brand: brand.trim() }, { site_id: siteId }, index);
21
21
  }
22
22
  case 'listLlmEngines': {
23
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/llm`, {}, {}, index);
23
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/airt/llm', {}, { site_id: siteId }, index);
24
24
  }
25
25
  case 'getLlmEngine': {
26
26
  const llmId = this.getNodeParameter('llmId', index);
27
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/llm/${llmId}`, {}, {}, index);
27
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/airt/llm', {}, { site_id: siteId, llm_id: llmId }, index);
28
28
  }
29
29
  case 'createLlmEngine': {
30
30
  const baseName = this.getNodeParameter('baseName', index);
@@ -38,7 +38,7 @@ async function AiResultTrackerOperations(index) {
38
38
  body.region_name = additionalFields.regionName;
39
39
  if (additionalFields.langCode)
40
40
  body.lang_code = additionalFields.langCode;
41
- return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/llm`, body, {}, index);
41
+ return await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/llm', body, { site_id: siteId }, index);
42
42
  }
43
43
  case 'updateLlmEngine': {
44
44
  const llmId = this.getNodeParameter('llmId', index);
@@ -48,38 +48,38 @@ async function AiResultTrackerOperations(index) {
48
48
  body.region_name = updateFields.regionName || null;
49
49
  if (updateFields.langCode !== undefined)
50
50
  body.lang_code = updateFields.langCode || null;
51
- return await apiRequest_1.apiRequest.call(this, 'PATCH', `/sites/${siteId}/airt/llm/${llmId}`, body, {}, index);
51
+ return await apiRequest_1.apiRequest.call(this, 'PATCH', `/project-management/airt/llm?site_id=${siteId}&llm_id=${llmId}`, body, {}, index);
52
52
  }
53
53
  case 'deleteLlmEngine': {
54
54
  const llmId = this.getNodeParameter('llmId', index);
55
- await apiRequest_1.apiRequest.call(this, 'DELETE', `/sites/${siteId}/airt/llm/${llmId}`, {}, {}, index);
55
+ await apiRequest_1.apiRequest.call(this, 'DELETE', '/project-management/airt/llm', {}, { site_id: siteId, llm_id: llmId }, index);
56
56
  return { success: true, deleted: true, llm_id: llmId };
57
57
  }
58
58
  case 'getLlmStatus': {
59
59
  const llmId = this.getNodeParameter('llmId', index);
60
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/llm/${llmId}/status`, {}, {}, index);
60
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/airt/llm/status', {}, { site_id: siteId, llm_id: llmId }, index);
61
61
  }
62
62
  case 'getLlmStatistics': {
63
63
  const llmId = this.getNodeParameter('llmId', index);
64
64
  const additionalFields = this.getNodeParameter('additionalFields', index, {});
65
- const query = {};
65
+ const query = { site_id: siteId, llm_id: llmId };
66
66
  if (additionalFields.from)
67
67
  query.from = additionalFields.from;
68
68
  if (additionalFields.to)
69
69
  query.to = additionalFields.to;
70
70
  if (additionalFields.top !== undefined)
71
71
  query.top = additionalFields.top;
72
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/llm/${llmId}/statistics`, {}, query, index);
72
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/airt/llm/statistics', {}, query, index);
73
73
  }
74
74
  case 'listPrompts': {
75
75
  const llmId = this.getNodeParameter('llmId', index);
76
76
  const additionalFields = this.getNodeParameter('additionalFields', index, {});
77
- const query = {};
77
+ const query = { site_id: siteId, llm_id: llmId };
78
78
  if (additionalFields.limit !== undefined)
79
79
  query.limit = additionalFields.limit;
80
80
  if (additionalFields.offset !== undefined)
81
81
  query.offset = additionalFields.offset;
82
- let endpoint = `/sites/${siteId}/airt/llm/${llmId}/prompts`;
82
+ let endpoint = '/project-management/airt/prompts';
83
83
  if (additionalFields.groupIds) {
84
84
  const ids = additionalFields.groupIds.split(',').map((id) => id.trim());
85
85
  endpoint += '?' + ids.map((id) => `group_ids[]=${encodeURIComponent(id)}`).join('&');
@@ -94,19 +94,19 @@ async function AiResultTrackerOperations(index) {
94
94
  const body = { prompts };
95
95
  if (additionalFields.groupId)
96
96
  body.group_id = additionalFields.groupId;
97
- return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/llm/${llmId}/prompts`, body, {}, index);
97
+ return await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/prompts', body, { site_id: siteId, llm_id: llmId }, index);
98
98
  }
99
99
  case 'deletePrompts': {
100
100
  const llmId = this.getNodeParameter('llmId', index);
101
101
  const idsStr = this.getNodeParameter('k2siteLlmIds', index);
102
102
  const k2siteLlmIds = idsStr.split(',').map((id) => parseInt(id.trim(), 10));
103
- await apiRequest_1.apiRequest.call(this, 'DELETE', `/sites/${siteId}/airt/llm/${llmId}/prompts`, { k2site_llm_ids: k2siteLlmIds }, {}, index);
103
+ await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/prompts/delete', { k2site_llm_ids: k2siteLlmIds }, { site_id: siteId, llm_id: llmId }, index);
104
104
  return { success: true, deleted: true, k2site_llm_ids: k2siteLlmIds };
105
105
  }
106
106
  case 'getPromptRankings': {
107
107
  const llmId = this.getNodeParameter('llmId', index);
108
108
  const additionalFields = this.getNodeParameter('additionalFields', index, {});
109
- const query = {};
109
+ const query = { site_id: siteId, llm_id: llmId };
110
110
  if (additionalFields.dateFrom)
111
111
  query.date_from = additionalFields.dateFrom;
112
112
  if (additionalFields.dateTo)
@@ -115,7 +115,9 @@ async function AiResultTrackerOperations(index) {
115
115
  query.limit = additionalFields.limit;
116
116
  if (additionalFields.offset !== undefined)
117
117
  query.offset = additionalFields.offset;
118
- let endpoint = `/sites/${siteId}/airt/llm/${llmId}/prompts/rankings`;
118
+ if (additionalFields.mode)
119
+ query.mode = additionalFields.mode;
120
+ let endpoint = '/project-management/airt/prompts/rankings';
119
121
  if (additionalFields.groupIds) {
120
122
  const ids = additionalFields.groupIds.split(',').map((id) => id.trim());
121
123
  endpoint += '?' + ids.map((id) => `group_ids[]=${encodeURIComponent(id)}`).join('&');
@@ -126,10 +128,10 @@ async function AiResultTrackerOperations(index) {
126
128
  const llmId = this.getNodeParameter('llmId', index);
127
129
  const k2siteLlmId = this.getNodeParameter('k2siteLlmId', index);
128
130
  const additionalFields = this.getNodeParameter('additionalFields', index, {});
129
- const query = {};
131
+ const query = { site_id: siteId, llm_id: llmId, k2site_llm_id: k2siteLlmId };
130
132
  if (additionalFields.date)
131
133
  query.date = additionalFields.date;
132
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/llm/${llmId}/prompts/${k2siteLlmId}/answer`, {}, query, index);
134
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/airt/prompts/answer', {}, query, index);
133
135
  }
134
136
  default:
135
137
  throw new Error(`Unknown AI Result Tracker operation: ${operation}`);
@@ -8,7 +8,7 @@ async function AirtGroupsOperations(index) {
8
8
  switch (operation) {
9
9
  case 'listPromptGroups': {
10
10
  const additionalFields = this.getNodeParameter('additionalFields', index, {});
11
- const query = {};
11
+ const query = { site_id: siteId };
12
12
  if (additionalFields.keysCount === true) {
13
13
  query.keys_count = 1;
14
14
  }
@@ -21,14 +21,14 @@ async function AirtGroupsOperations(index) {
21
21
  query['site_llm_ids[]'] = ids;
22
22
  }
23
23
  }
24
- return await apiRequest_1.apiRequest.call(this, 'GET', `/sites/${siteId}/airt/prompt-groups`, {}, query, index);
24
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/airt/prompts/groups', {}, query, index);
25
25
  }
26
26
  case 'createPromptGroup': {
27
27
  const name = this.getNodeParameter('groupName', index);
28
28
  if (!name || name.trim() === '') {
29
29
  throw new Error('Group name cannot be empty');
30
30
  }
31
- return await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups`, { name: name.trim() }, {}, index);
31
+ return await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/prompts/groups', { name: name.trim() }, { site_id: siteId }, index);
32
32
  }
33
33
  case 'renamePromptGroup': {
34
34
  const groupId = this.getNodeParameter('groupId', index);
@@ -36,11 +36,11 @@ async function AirtGroupsOperations(index) {
36
36
  if (!name || name.trim() === '') {
37
37
  throw new Error('Group name cannot be empty');
38
38
  }
39
- return await apiRequest_1.apiRequest.call(this, 'PATCH', `/sites/${siteId}/airt/prompt-groups/${groupId}`, { name: name.trim() }, {}, index);
39
+ return await apiRequest_1.apiRequest.call(this, 'PATCH', `/project-management/airt/prompts/groups?site_id=${siteId}&group_id=${groupId}`, { name: name.trim() }, {}, index);
40
40
  }
41
41
  case 'deletePromptGroup': {
42
42
  const groupId = this.getNodeParameter('groupId', index);
43
- await apiRequest_1.apiRequest.call(this, 'DELETE', `/sites/${siteId}/airt/prompt-groups/${groupId}`, {}, {}, index);
43
+ await apiRequest_1.apiRequest.call(this, 'DELETE', '/project-management/airt/prompts/groups', {}, { site_id: siteId, group_id: groupId }, index);
44
44
  return { success: true, deleted: true, group_id: groupId };
45
45
  }
46
46
  case 'changeGroupOrder': {
@@ -57,12 +57,12 @@ async function AirtGroupsOperations(index) {
57
57
  body.before_id = beforeId;
58
58
  if (hasAfter)
59
59
  body.after_id = afterId;
60
- await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups/${groupId}/order`, body, {}, index);
60
+ await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/prompts/groups/order', body, { site_id: siteId, group_id: groupId }, index);
61
61
  return { success: true, group_id: groupId, ...body };
62
62
  }
63
63
  case 'deleteAllPromptsInGroup': {
64
64
  const groupId = this.getNodeParameter('groupId', index);
65
- await apiRequest_1.apiRequest.call(this, 'DELETE', `/sites/${siteId}/airt/prompt-groups/${groupId}/keywords`, {}, {}, index);
65
+ await apiRequest_1.apiRequest.call(this, 'DELETE', '/project-management/airt/prompts/groups/prompts', {}, { site_id: siteId, group_id: groupId }, index);
66
66
  return { success: true, emptied: true, group_id: groupId };
67
67
  }
68
68
  case 'movePromptsToGroup': {
@@ -75,7 +75,7 @@ async function AirtGroupsOperations(index) {
75
75
  if (ids.length === 0) {
76
76
  throw new Error('Provide at least one k2site_llm_id');
77
77
  }
78
- await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups/${groupId}/moveKeywords`, { k2site_llm_ids: ids }, {}, index);
78
+ await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/prompts/groups/move', { k2site_llm_ids: ids }, { site_id: siteId, group_id: groupId }, index);
79
79
  return { success: true, group_id: groupId, moved: ids };
80
80
  }
81
81
  case 'moveAllPromptsBetweenGroups': {
@@ -84,7 +84,7 @@ async function AirtGroupsOperations(index) {
84
84
  if (fromGroupId === toGroupId) {
85
85
  throw new Error('Source and Target Group ID must differ');
86
86
  }
87
- await apiRequest_1.apiRequest.call(this, 'POST', `/sites/${siteId}/airt/prompt-groups/moveGroupKeywords`, { from_group_id: fromGroupId, to_group_id: toGroupId }, {}, index);
87
+ await apiRequest_1.apiRequest.call(this, 'POST', '/project-management/airt/prompts/groups/transfer', { from_group_id: fromGroupId, to_group_id: toGroupId }, { site_id: siteId }, index);
88
88
  return { success: true, from_group_id: fromGroupId, to_group_id: toGroupId };
89
89
  }
90
90
  default: