@seranking/n8n-nodes-seranking 2.0.3 → 2.0.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # n8n-nodes-seranking
2
2
 
3
- n8n community node for [SE Ranking](https://seranking.com/)'s unified API — 190 operations across 21 resources: AI Search, Backlinks, Domain Analysis, Keyword Research, SERP Classic, Website Audits, Project Management, Competitors, Backlink Checker, Sub-Accounts, and more.
3
+ n8n community node for [SE Ranking](https://seranking.com/)'s unified API — 194 operations across 21 resources: AI Search, Backlinks, Domain Analysis, Keyword Research, SERP Classic, Website Audits, Project Management, Competitors, Backlink Checker, Sub-Accounts, and more.
4
4
 
5
5
  SE Ranking is a comprehensive SEO platform providing keyword research, competitor analysis, website audits, backlink monitoring, and AI search visibility tracking.
6
6
 
@@ -187,7 +187,7 @@ If you're upgrading and have saved credentials of type `seRankingProjectApi`, yo
187
187
 
188
188
  ## Operations
189
189
 
190
- This node provides access to **21 SE Ranking resources** with **190 total operations** on the unified API:
190
+ This node provides access to **21 SE Ranking resources** with **194 total operations** on the unified API:
191
191
 
192
192
  ### Data API (6 resources, 65 operations)
193
193
 
@@ -279,7 +279,7 @@ This node provides access to **21 SE Ranking resources** with **190 total operat
279
279
 
280
280
  ### Project API (14 resources, 107 operations)
281
281
 
282
- ### Project Management (17 operations)
282
+ ### Project Management (20 operations)
283
283
 
284
284
  - List Projects - Get all projects
285
285
  - Add Project - Create a new project
@@ -386,7 +386,7 @@ This node provides access to **21 SE Ranking resources** with **190 total operat
386
386
  - Set Task Status - Mark task as complete/incomplete
387
387
  - Delete Task - Remove a custom task
388
388
 
389
- ### Website Audit (Project) (12 operations)
389
+ ### Website Audit (Project) (21 operations)
390
390
 
391
391
  - Create Audit - Launch a website audit
392
392
  - List Audits - Get all audits
@@ -739,7 +739,7 @@ For detailed API specifications, visit [SE Ranking API Documentation](https://se
739
739
  * 🐛 **FIX: Update Audit Title** — was returning 400 since April 2026, now works
740
740
  * 🐛 **FIX: Run Position Check** — /api/ prefix bug resolved by unification
741
741
  * ⚠️ **Deprecated: Search Volume + Volume Regions** — 6 ops return 404 on unified host (friendly error with guidance)
742
- * 📊 **Total: 190 operations across 21 resources**
742
+ * 📊 **Total: 192 operations across 21 resources**
743
743
 
744
744
  ### v1.5.13
745
745
 
@@ -826,7 +826,7 @@ For detailed API specifications, visit [SE Ranking API Documentation](https://se
826
826
 
827
827
  ## Features
828
828
 
829
- ✅ **190 Operations** - Comprehensive coverage across 21 resources (unified API)
829
+ ✅ **192 Operations** - Comprehensive coverage across 21 resources (unified API)
830
830
 
831
831
  ✅ **Pingback Webhooks** - Event-driven notifications for SERP task completion
832
832
 
@@ -151,6 +151,12 @@ exports.backlinksOperations = [
151
151
  description: 'Get distribution of domain authority scores among linking domains',
152
152
  action: 'Get domain authority distribution',
153
153
  },
154
+ {
155
+ name: 'Get Domain Authority History',
156
+ value: 'getDomainAuthorityHistory',
157
+ description: 'Get historical Domain InLink Rank values for the target domain',
158
+ action: 'Get domain authority history',
159
+ },
154
160
  {
155
161
  name: 'Get Page Authority',
156
162
  value: 'getPageAuthority',
@@ -197,6 +203,7 @@ exports.backlinksFields = [
197
203
  'getAuthority',
198
204
  'getDomainAuthority',
199
205
  'getDomainAuthorityDistribution',
206
+ 'getDomainAuthorityHistory',
200
207
  'getPageAuthority',
201
208
  'getPageAuthorityHistory',
202
209
  ],
@@ -300,6 +307,7 @@ exports.backlinksFields = [
300
307
  'getRefDomainsHistory',
301
308
  'getRefDomainsHistoryCount',
302
309
  'getPageAuthorityHistory',
310
+ 'getDomainAuthorityHistory',
303
311
  ],
304
312
  },
305
313
  },
@@ -322,6 +330,7 @@ exports.backlinksFields = [
322
330
  'getRefDomainsHistory',
323
331
  'getRefDomainsHistoryCount',
324
332
  'getPageAuthorityHistory',
333
+ 'getDomainAuthorityHistory',
325
334
  ],
326
335
  },
327
336
  },
@@ -306,6 +306,19 @@ async function BacklinksOperations(index) {
306
306
  params.target = target;
307
307
  break;
308
308
  }
309
+ case 'getDomainAuthorityHistory': {
310
+ const target = this.getNodeParameter('target', index);
311
+ const dateFrom = this.getNodeParameter('dateFrom', index);
312
+ const dateTo = this.getNodeParameter('dateTo', index);
313
+ if (!(0, validators_1.validateDateFormat)(dateFrom) || !(0, validators_1.validateDateFormat)(dateTo)) {
314
+ throw new Error('Date must be in YYYY-MM-DD format');
315
+ }
316
+ endpoint = '/backlinks/authority/domain/history';
317
+ params.target = target;
318
+ params.date_from = dateFrom;
319
+ params.date_to = dateTo;
320
+ break;
321
+ }
309
322
  case 'getPageAuthority': {
310
323
  const target = this.getNodeParameter('target', index);
311
324
  endpoint = '/backlinks/authority/page';
@@ -25,6 +25,12 @@ exports.generalDataOperations = [
25
25
  description: 'Get a list of supported languages for Google',
26
26
  action: 'List languages for Google',
27
27
  },
28
+ {
29
+ name: 'List Regions for Google',
30
+ value: 'listGoogleRegions',
31
+ description: 'Get a list of Google regions (region ID + name) for location targeting',
32
+ action: 'List regions for Google',
33
+ },
28
34
  {
29
35
  name: 'List Search Engines',
30
36
  value: 'listSearchEngines',
@@ -133,6 +133,12 @@ exports.projectManagementOperations = [
133
133
  description: 'Remove a search engine configuration from a project',
134
134
  action: 'Delete search engine from project',
135
135
  },
136
+ {
137
+ name: 'Edit Keyword',
138
+ value: 'editKeyword',
139
+ description: 'Update fields of an existing keyword in a project',
140
+ action: 'Edit keyword',
141
+ },
136
142
  {
137
143
  name: 'Get Ads Chart',
138
144
  value: 'getAds',
@@ -230,6 +236,7 @@ exports.projectManagementFields = [
230
236
  'runRecheck',
231
237
  'listCheckDates',
232
238
  'getRankingTrends',
239
+ 'editKeyword',
233
240
  ],
234
241
  },
235
242
  },
@@ -709,6 +716,83 @@ exports.projectManagementFields = [
709
716
  placeholder: '1,2,3',
710
717
  description: 'Comma-separated keyword IDs to delete',
711
718
  },
719
+ {
720
+ displayName: 'Keyword ID',
721
+ name: 'editKeywordId',
722
+ type: 'number',
723
+ required: true,
724
+ displayOptions: {
725
+ show: {
726
+ resource: ['projectManagement'],
727
+ operation: ['editKeyword'],
728
+ },
729
+ },
730
+ default: 0,
731
+ description: 'Unique ID of the keyword to edit',
732
+ },
733
+ {
734
+ displayName: 'Update Fields',
735
+ name: 'updateFields',
736
+ type: 'collection',
737
+ placeholder: 'Add Field',
738
+ default: {},
739
+ displayOptions: {
740
+ show: {
741
+ resource: ['projectManagement'],
742
+ operation: ['editKeyword'],
743
+ },
744
+ },
745
+ description: 'Fields to update. Provide at least one (the API rejects an empty update, and a comment alone is not accepted — include Keyword or Group ID).',
746
+ options: [
747
+ {
748
+ displayName: 'Keyword',
749
+ name: 'keyword',
750
+ type: 'string',
751
+ default: '',
752
+ description: 'The keyword text',
753
+ },
754
+ {
755
+ displayName: 'Group ID',
756
+ name: 'group_id',
757
+ type: 'number',
758
+ default: 0,
759
+ description: 'Keyword group ID to move the keyword into',
760
+ },
761
+ {
762
+ displayName: 'Target URL',
763
+ name: 'target_url',
764
+ type: 'string',
765
+ default: '',
766
+ description: 'Target landing-page URL for the keyword',
767
+ },
768
+ {
769
+ displayName: 'Strict URL Match',
770
+ name: 'is_strict',
771
+ type: 'options',
772
+ options: [
773
+ { name: 'No', value: 0 },
774
+ { name: 'Yes', value: 1 },
775
+ ],
776
+ default: 0,
777
+ description: 'Whether to require a strict match of the target URL',
778
+ },
779
+ {
780
+ displayName: 'Comment',
781
+ name: 'comment',
782
+ type: 'string',
783
+ default: '',
784
+ description: 'Free-text note for the keyword',
785
+ },
786
+ {
787
+ displayName: 'Search Engine IDs',
788
+ name: 'site_engine_ids',
789
+ type: 'string',
790
+ default: '',
791
+ placeholder: '1149319,1149320',
792
+ description: 'Comma-separated search engine (site_engine_id) values to assign',
793
+ },
794
+ ],
795
+ },
712
796
  {
713
797
  displayName: 'Keyword ID',
714
798
  name: 'keywordId',
@@ -133,6 +133,12 @@ exports.websiteAuditOperations = [
133
133
  description: 'Remove an uploaded custom page list',
134
134
  action: 'Delete audit source pages',
135
135
  },
136
+ {
137
+ name: 'Add Audit Source Pages',
138
+ value: 'addAuditSourcePages',
139
+ description: 'Upload a .txt list of URLs (one per line) as a custom page list',
140
+ action: 'Add audit source pages',
141
+ },
136
142
  ],
137
143
  default: 'listAudits',
138
144
  },
@@ -146,7 +152,7 @@ exports.websiteAuditFields = [
146
152
  displayOptions: {
147
153
  show: {
148
154
  resource: ['websiteAuditProject'],
149
- operation: ['getStatus', 'getReport', 'getPages', 'getPagesByIssue', 'getIssues', 'getLinks', 'getHistory', 'updateTitle', 'deleteAudit', 'recheckAudit', 'getAuditSettings', 'updateAuditSettings', 'resetAuditSettings', 'listAuditSitemaps', 'addAuditSitemap', 'deleteAuditSitemap', 'listAuditSourcePages', 'deleteAuditSourcePages'],
155
+ operation: ['getStatus', 'getReport', 'getPages', 'getPagesByIssue', 'getIssues', 'getLinks', 'getHistory', 'updateTitle', 'deleteAudit', 'recheckAudit', 'getAuditSettings', 'updateAuditSettings', 'resetAuditSettings', 'listAuditSitemaps', 'addAuditSitemap', 'deleteAuditSitemap', 'listAuditSourcePages', 'deleteAuditSourcePages', 'addAuditSourcePages'],
150
156
  },
151
157
  },
152
158
  default: 0,
@@ -485,4 +491,18 @@ exports.websiteAuditFields = [
485
491
  default: '',
486
492
  description: 'ID of the uploaded page list to remove (from List Audit Source Pages)',
487
493
  },
494
+ {
495
+ displayName: 'Input Binary Field',
496
+ name: 'binaryPropertyName',
497
+ type: 'string',
498
+ required: true,
499
+ default: 'data',
500
+ displayOptions: {
501
+ show: {
502
+ resource: ['websiteAuditProject'],
503
+ operation: ['addAuditSourcePages'],
504
+ },
505
+ },
506
+ description: 'Name of the binary property holding the UTF-8 .txt file (one URL per line) to upload',
507
+ },
488
508
  ];
@@ -11,6 +11,9 @@ async function GeneralDataOperations(index) {
11
11
  case 'listGoogleLangs': {
12
12
  return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/system/google/languages', {}, {}, index);
13
13
  }
14
+ case 'listGoogleRegions': {
15
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/system/google/regions', {}, {}, index);
16
+ }
14
17
  case 'listVolumeRegions': {
15
18
  throw new Error('listVolumeRegions: The /system/volume-regions endpoint is not available under the unified API (HTTP 404 as of 2026-05-22). ' +
16
19
  'SE Ranking has not yet published a replacement in the unified docs. ' +
@@ -145,6 +145,29 @@ async function ProjectManagementOperations(index) {
145
145
  await apiRequest_1.apiRequest.call(this, 'DELETE', '/project-management/keywords', {}, query, index);
146
146
  return { success: true, deleted: true, keyword_ids: keywordIds };
147
147
  }
148
+ case 'editKeyword': {
149
+ const siteId = this.getNodeParameter('siteId', index);
150
+ const keywordId = this.getNodeParameter('editKeywordId', index);
151
+ const updateFields = this.getNodeParameter('updateFields', index, {});
152
+ const body = {};
153
+ if (updateFields.keyword)
154
+ body.keyword = updateFields.keyword;
155
+ if (updateFields.group_id)
156
+ body.group_id = updateFields.group_id;
157
+ if (updateFields.target_url)
158
+ body.target_url = updateFields.target_url;
159
+ if (updateFields.is_strict !== undefined)
160
+ body.is_strict = updateFields.is_strict;
161
+ if (updateFields.comment !== undefined && updateFields.comment !== '')
162
+ body.comment = updateFields.comment;
163
+ if (updateFields.site_engine_ids) {
164
+ body.site_engine_ids = String(updateFields.site_engine_ids)
165
+ .split(',')
166
+ .map((v) => parseInt(v.trim(), 10));
167
+ }
168
+ await apiRequest_1.apiRequest.call(this, 'PATCH', `/project-management/keywords?site_id=${siteId}&keyword_id=${keywordId}`, body, {}, index);
169
+ return { success: true, keyword_id: keywordId, updated: Object.keys(body) };
170
+ }
148
171
  case 'getStats': {
149
172
  const siteId = this.getNodeParameter('siteId', index);
150
173
  return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/sites/summary', {}, { site_id: siteId }, index);
@@ -154,14 +154,28 @@ async function WebsiteAuditOperations(index) {
154
154
  }
155
155
  case 'listAuditSourcePages': {
156
156
  const auditId = this.getNodeParameter('auditId', index);
157
- return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/audits/source_pages', {}, { audit_id: auditId }, index);
157
+ return await apiRequest_1.apiRequest.call(this, 'GET', '/project-management/audits/source-pages', {}, { audit_id: auditId }, index);
158
158
  }
159
159
  case 'deleteAuditSourcePages': {
160
160
  const auditId = this.getNodeParameter('auditId', index);
161
161
  const listId = this.getNodeParameter('sourcePagesListId', index);
162
- await apiRequest_1.apiRequest.call(this, 'DELETE', '/project-management/audits/source_pages', {}, { audit_id: auditId, list_id: listId }, index);
162
+ await apiRequest_1.apiRequest.call(this, 'DELETE', '/project-management/audits/source-pages', {}, { audit_id: auditId, list_id: listId }, index);
163
163
  return { success: true, deleted: true, list_id: listId };
164
164
  }
165
+ case 'addAuditSourcePages': {
166
+ const auditId = this.getNodeParameter('auditId', index);
167
+ const binaryPropertyName = this.getNodeParameter('binaryPropertyName', index);
168
+ const binaryData = this.helpers.assertBinaryData(index, binaryPropertyName);
169
+ const buffer = await this.helpers.getBinaryDataBuffer(index, binaryPropertyName);
170
+ return await apiRequest_1.apiRequest.call(this, 'POST', `/project-management/audits/source-pages?audit_id=${auditId}`, {
171
+ _fileUpload: {
172
+ fieldName: 'file',
173
+ filename: binaryData.fileName || 'source-pages.txt',
174
+ contentType: 'text/plain',
175
+ data: buffer,
176
+ },
177
+ }, {}, index);
178
+ }
165
179
  default:
166
180
  throw new Error(`Unknown Website Audit operation: ${operation}`);
167
181
  }
@@ -62,7 +62,21 @@ async function apiRequest(method, endpoint, body = {}, query = {}, itemIndex = 0
62
62
  }
63
63
  }
64
64
  if (method !== 'GET' && body != null && (Array.isArray(body) || Object.keys(body).length > 0)) {
65
- if (body.keywords && Array.isArray(body.keywords)) {
65
+ if (body._fileUpload) {
66
+ const f = body._fileUpload;
67
+ const boundary = `----serankingFormBoundary${Date.now().toString(16)}`;
68
+ const preamble = Buffer.from(`--${boundary}\r\n` +
69
+ `Content-Disposition: form-data; name="${f.fieldName}"; filename="${f.filename}"\r\n` +
70
+ `Content-Type: ${f.contentType}\r\n\r\n`);
71
+ const epilogue = Buffer.from(`\r\n--${boundary}--\r\n`);
72
+ options.body = Buffer.concat([preamble, f.data, epilogue]);
73
+ options.headers = {
74
+ ...options.headers,
75
+ 'Content-Type': `multipart/form-data; boundary=${boundary}`,
76
+ };
77
+ options.json = false;
78
+ }
79
+ else if (body.keywords && Array.isArray(body.keywords)) {
66
80
  const formDataBody = {};
67
81
  body.keywords.forEach((kw, index) => {
68
82
  formDataBody[`keywords[${index}]`] = kw;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@seranking/n8n-nodes-seranking",
3
- "version": "2.0.3",
4
- "description": "n8n community node for SE Ranking's unified API — 190 operations across 21 resources: AI Search, Backlinks, Domain Analysis, Keyword Research, SERP Classic, Website Audits, Project Management, Competitors, Backlink Checker, Sub-Accounts, and more",
3
+ "version": "2.0.5",
4
+ "description": "n8n community node for SE Ranking's unified API — 194 operations across 21 resources: AI Search, Backlinks, Domain Analysis, Keyword Research, SERP Classic, Website Audits, Project Management, Competitors, Backlink Checker, Sub-Accounts, and more",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/seranking/n8n-nodes-seranking",
7
7
  "author": {