Count which selected topic keywords a bulk action applies to
curl --request POST \
--url https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"selection": {
"mode": "ids",
"ids": [
"<string>"
]
},
"teamId": "<string>",
"topicId": "<string>",
"startDate": "<string>",
"endDate": "<string>",
"targetTopicId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
'import requests
url = "https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview"
payload = {
"selection": {
"mode": "ids",
"ids": ["<string>"]
},
"teamId": "<string>",
"topicId": "<string>",
"startDate": "<string>",
"endDate": "<string>",
"targetTopicId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
selection: {mode: 'ids', ids: ['<string>']},
teamId: '<string>',
topicId: '<string>',
startDate: '<string>',
endDate: '<string>',
targetTopicId: '3c90c3cc-0d44-4b50-8888-8dd25736052a'
})
};
fetch('https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'selection' => [
'mode' => 'ids',
'ids' => [
'<string>'
]
],
'teamId' => '<string>',
'topicId' => '<string>',
'startDate' => '<string>',
'endDate' => '<string>',
'targetTopicId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview"
payload := strings.NewReader("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\",\n \"topicId\": \"<string>\",\n \"startDate\": \"<string>\",\n \"endDate\": \"<string>\",\n \"targetTopicId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\",\n \"topicId\": \"<string>\",\n \"startDate\": \"<string>\",\n \"endDate\": \"<string>\",\n \"targetTopicId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\",\n \"topicId\": \"<string>\",\n \"startDate\": \"<string>\",\n \"endDate\": \"<string>\",\n \"targetTopicId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}"
response = http.request(request)
puts response.read_body{
"eligibility": {
"selected": 123,
"eligible": 123,
"skipped": 123,
"byReason": {}
}
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}Topic Clusters
Bulk topic keyword actions
Preview, track, untrack, remove, or move many keywords of a topic cluster at once.
POST
/
v3
/
topic-clusters
/
topic-keywords
/
bulk-preview
Count which selected topic keywords a bulk action applies to
curl --request POST \
--url https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"selection": {
"mode": "ids",
"ids": [
"<string>"
]
},
"teamId": "<string>",
"topicId": "<string>",
"startDate": "<string>",
"endDate": "<string>",
"targetTopicId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
'import requests
url = "https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview"
payload = {
"selection": {
"mode": "ids",
"ids": ["<string>"]
},
"teamId": "<string>",
"topicId": "<string>",
"startDate": "<string>",
"endDate": "<string>",
"targetTopicId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
selection: {mode: 'ids', ids: ['<string>']},
teamId: '<string>',
topicId: '<string>',
startDate: '<string>',
endDate: '<string>',
targetTopicId: '3c90c3cc-0d44-4b50-8888-8dd25736052a'
})
};
fetch('https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'selection' => [
'mode' => 'ids',
'ids' => [
'<string>'
]
],
'teamId' => '<string>',
'topicId' => '<string>',
'startDate' => '<string>',
'endDate' => '<string>',
'targetTopicId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview"
payload := strings.NewReader("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\",\n \"topicId\": \"<string>\",\n \"startDate\": \"<string>\",\n \"endDate\": \"<string>\",\n \"targetTopicId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\",\n \"topicId\": \"<string>\",\n \"startDate\": \"<string>\",\n \"endDate\": \"<string>\",\n \"targetTopicId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/topic-clusters/topic-keywords/bulk-preview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"selection\": {\n \"mode\": \"ids\",\n \"ids\": [\n \"<string>\"\n ]\n },\n \"teamId\": \"<string>\",\n \"topicId\": \"<string>\",\n \"startDate\": \"<string>\",\n \"endDate\": \"<string>\",\n \"targetTopicId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n}"
response = http.request(request)
puts response.read_body{
"eligibility": {
"selected": 123,
"eligible": 123,
"skipped": 123,
"byReason": {}
}
}{
"success": true,
"error": "<string>",
"code": "<string>",
"message": "<string>",
"reference": "<string>"
}Every bulk action works on the keywords of one topic cluster (
A move is skipped for every row, and nothing moves, while any selected keyword is already in the target or no longer in the source.
Each call processes one batch and returns
topicId, required) and takes a selection:
selectionis either{ mode: "ids", ids: [keywordId, ...] }or{ mode: "all", filters: { search?, category? }, excludedIds: [...] }.categoryisAll,RankedorMentioned; passstartDateandendDateto set the metrics window those filters read.- Call
POST /v3/topic-clusters/topic-keywords/bulk-previewwith theselection,topicIdand anactionfirst. It changes nothing and returnseligibility:{ selected, eligible, skipped, byReason }. Formove, also passtargetTopicId.
| Action | Endpoint | Rows per call | Extra body |
|---|---|---|---|
| Track | POST /v3/topic-clusters/topic-keywords/bulk-track | 10 | none; consumes keyword-tracking allowance, returns 402 at the limit |
| Untrack | POST /v3/topic-clusters/topic-keywords/bulk-untrack | 50 | none |
| Remove | POST /v3/topic-clusters/topic-keywords/bulk-remove | 50 | none; unlinks only, the keywords stay |
| Move | POST /v3/topic-clusters/topic-keywords/bulk-move | 50 | targetTopicId (required) |
{ success, succeeded, failed, nextCursor, eligibility, results }. While nextCursor is not null, call again with the same body and afterId set to nextCursor. results has one entry per keyword with id, keyword, success and error when it failed.
For a single keyword, use Topic Keywords to add or DELETE /v3/topic-clusters/{topicId}/keywords/{keywordId} to remove.Authorizations
bearerAuthapiKey
Your SnowSEO API key (sk_...).
Body
application/json
- Option 1
- Option 2
Show child attributes
Show child attributes
The bulk action to count eligible rows for.
Available options:
track, untrack, remove, move Topic cluster the rows belong to.
Start of the metrics window the selection filters read (YYYY-MM-DD).
End of the metrics window the selection filters read (YYYY-MM-DD).
Topic cluster to move the rows into.
Response
Default Response
Show child attributes
Show child attributes
Was this page helpful?

