Dashboard Campaigns
21 endpoints from the published OpenAPI import.
Get Quota Status
Get the current campaign quota status for the authenticated client.
Returns remaining quotas for daily, monthly, and concurrent campaigns. For super_admin without a selected client, returns unlimited quotas.
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/quota' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/quota",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/quota", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/quota", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
List Active Locations
Return lat/lng dots for the Live Theater Tactical Map.
V1.0 (default flags off, back-compat): just queued/in-progress location dots (gray). Powers the queued layer when a campaign first starts.
V1.1 (flags on): full geographic state of the user's active campaigns. Adds dim-gold completed-location dots (persist while campaign is active) and bright-gold per-business dots (one per business found at each location). Solves the "map empty after dots age out of SSE buffer" UX bug.
Multi-tenant scoped:
- super_admin + X-Selected-Client-Id → that client
- super_admin + X-Brand-ID only → all clients in that brand
- super_admin without scope → empty list
- client_user / brand_admin w/ client_id → that client
- brand-scoped user (client_id NULL, brand_id set) → all clients in that brand
- non-super_admin without scope → empty list
Total response capped at 5000 rows when include_businesses=true, 500 otherwise.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
include_completed | query | boolean | false | If true, also return dim-gold dots for completed locations of active campaigns. |
include_businesses | query | boolean | false | If true, also return bright-gold per-business dots from public.results.data->'businesses'. |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/active-locations' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/active-locations",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/active-locations", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/active-locations", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
List Campaigns
List campaigns for the authenticated client.
For super_admin: Can filter by X-Selected-Client-Id or X-Brand-ID header. For client_user/brand_admin: Filter by X-Brand-ID header or their client_id.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
page | query | integer | false | |
page_size | query | integer | false | |
status | query | any | false | |
country_code | query | any | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Create Campaign
Create a new SpiderMaps campaign.
Enforces quota limits before creation.
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"search_query": "string",
"query": "string",
"country_code": "string",
"name": "string",
"filter": {
"mode": "all",
"min_population": 0,
"max_population": 0,
"location_ids": [
0
],
"admin_regions": [
"string"
],
"parent_city": "string",
"include_postcodes": false,
"exhaustive": false
},
"max_results": 100,
"extract_reviews": false,
"extract_photos": false,
"lang": "en",
"store_images": true,
"validate_phones": true,
"fuzziq_enabled": true,
"fuzziq_unique_only": true,
"skip_proxy": false,
"test": false,
"workflow": {
"spidersite": {
"enabled": false,
"mode": {},
"max_pages": 25,
"crawl_strategy": "bestfirst",
"target_pages": [
"contact",
"about",
"team",
"news",
"blog"
],
"enable_spa": true,
"spa_timeout": 30,
"extract_team": false,
"extract_company_info": false,
"extract_pain_points": false,
"product_description": {},
"icp_description": {},
"compendium": {},
"timeout": 30
},
"spiderverify": {
"enabled": false,
"check_gravatar": false,
"check_dnsbl": false,
"smtp_timeout_secs": 45,
"max_emails_per_business": 10
},
"vayapin": {
"enabled": false
},
"social_media_enrichment": {
"enabled": true
},
"smartlead": {
"enabled": false,
"connection_id": {},
"remote_campaign_id": {},
"remote_campaign_name": {},
"limit": {},
"only_with_vayapin_seo": false,
"only_with_vayapin_pin": false,
"field_map": {}
},
"filter_social_media": true,
"filter_review_sites": true,
"filter_directories": true,
"filter_maps": true
}
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"search_query": "string", "query": "string", "country_code": "string", "name": "string", "filter": {"mode": "all", "min_population": 0, "max_population": 0, "location_ids": [0], "admin_regions": ["string"], "parent_city": "string", "include_postcodes": false, "exhaustive": false}, "max_results": 100, "extract_reviews": false, "extract_photos": false, "lang": "en", "store_images": true, "validate_phones": true, "fuzziq_enabled": true, "fuzziq_unique_only": true, "skip_proxy": false, "test": false, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"search_query": "string", "query": "string", "country_code": "string", "name": "string", "filter": {"mode": "all", "min_population": 0, "max_population": 0, "location_ids": [0], "admin_regions": ["string"], "parent_city": "string", "include_postcodes": false, "exhaustive": false}, "max_results": 100, "extract_reviews": false, "extract_photos": false, "lang": "en", "store_images": true, "validate_phones": true, "fuzziq_enabled": true, "fuzziq_unique_only": true, "skip_proxy": false, "test": false, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"search_query": "string", "query": "string", "country_code": "string", "name": "string", "filter": {"mode": "all", "min_population": 0, "max_population": 0, "location_ids": [0], "admin_regions": ["string"], "parent_city": "string", "include_postcodes": false, "exhaustive": false}, "max_results": 100, "extract_reviews": false, "extract_photos": false, "lang": "en", "store_images": true, "validate_phones": true, "fuzziq_enabled": true, "fuzziq_unique_only": true, "skip_proxy": false, "test": false, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
201 | Successful Response |
422 | Validation Error |
Estimate Campaign
Pre-flight campaign estimate for the dashboard create flow.
Writes NO rows and is NOT a dispatcher submission. Returns the location count plus per-stage billable-job COUNTS (not USD). requires_upgrade is layered with the client's real per-plan max_locations so the create UI can show Proceed vs Upgrade.
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns/estimate' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"search_query": "string",
"country_code": "string",
"filter": {
"mode": "all",
"min_population": 0,
"max_population": 0,
"location_ids": [
0
],
"admin_regions": [
"string"
],
"parent_city": "string",
"include_postcodes": false,
"exhaustive": false
},
"max_results": 100,
"workflow": {
"spidersite": {
"enabled": false,
"mode": {},
"max_pages": 25,
"crawl_strategy": "bestfirst",
"target_pages": [
"contact",
"about",
"team",
"news",
"blog"
],
"enable_spa": true,
"spa_timeout": 30,
"extract_team": false,
"extract_company_info": false,
"extract_pain_points": false,
"product_description": {},
"icp_description": {},
"compendium": {},
"timeout": 30
},
"spiderverify": {
"enabled": false,
"check_gravatar": false,
"check_dnsbl": false,
"smtp_timeout_secs": 45,
"max_emails_per_business": 10
},
"vayapin": {
"enabled": false
},
"social_media_enrichment": {
"enabled": true
},
"smartlead": {
"enabled": false,
"connection_id": {},
"remote_campaign_id": {},
"remote_campaign_name": {},
"limit": {},
"only_with_vayapin_seo": false,
"only_with_vayapin_pin": false,
"field_map": {}
},
"filter_social_media": true,
"filter_review_sites": true,
"filter_directories": true,
"filter_maps": true
}
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/estimate",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"search_query": "string", "country_code": "string", "filter": {"mode": "all", "min_population": 0, "max_population": 0, "location_ids": [0], "admin_regions": ["string"], "parent_city": "string", "include_postcodes": false, "exhaustive": false}, "max_results": 100, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/estimate", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"search_query": "string", "country_code": "string", "filter": {"mode": "all", "min_population": 0, "max_population": 0, "location_ids": [0], "admin_regions": ["string"], "parent_city": "string", "include_postcodes": false, "exhaustive": false}, "max_results": 100, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"search_query": "string", "country_code": "string", "filter": {"mode": "all", "min_population": 0, "max_population": 0, "location_ids": [0], "admin_regions": ["string"], "parent_city": "string", "include_postcodes": false, "exhaustive": false}, "max_results": 100, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns/estimate", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Campaign Status
Get detailed status for a specific campaign.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Update Campaign
Update an existing campaign's configuration.
What can be updated:
search_query- Changes search term for future jobsname- Campaign display name- SpiderMaps options (max_results, extract_reviews, etc.)
workflow- Workflow configuration (merged with existing)
Restrictions:
- Only active or stopped/paused campaigns can be updated
- Completed campaigns cannot be modified
- Changes only affect PENDING locations
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true |
Try it
Examples
cURL
curl -X PATCH 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"search_query": "string",
"query": "string",
"name": "string",
"max_results": 0,
"extract_reviews": true,
"extract_photos": true,
"lang": "string",
"store_images": true,
"validate_phones": true,
"fuzziq_enabled": true,
"fuzziq_unique_only": true,
"skip_proxy": true,
"test": true,
"workflow": {
"spidersite": {
"enabled": false,
"mode": {},
"max_pages": 25,
"crawl_strategy": "bestfirst",
"target_pages": [
"contact",
"about",
"team",
"news",
"blog"
],
"enable_spa": true,
"spa_timeout": 30,
"extract_team": false,
"extract_company_info": false,
"extract_pain_points": false,
"product_description": {},
"icp_description": {},
"compendium": {},
"timeout": 30
},
"spiderverify": {
"enabled": false,
"check_gravatar": false,
"check_dnsbl": false,
"smtp_timeout_secs": 45,
"max_emails_per_business": 10
},
"vayapin": {
"enabled": false
},
"social_media_enrichment": {
"enabled": true
},
"smartlead": {
"enabled": false,
"connection_id": {},
"remote_campaign_id": {},
"remote_campaign_name": {},
"limit": {},
"only_with_vayapin_seo": false,
"only_with_vayapin_pin": false,
"field_map": {}
},
"filter_social_media": true,
"filter_review_sites": true,
"filter_directories": true,
"filter_maps": true
}
}'Python
import httpx
resp = httpx.patch(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"search_query": "string", "query": "string", "name": "string", "max_results": 0, "extract_reviews": true, "extract_photos": true, "lang": "string", "store_images": true, "validate_phones": true, "fuzziq_enabled": true, "fuzziq_unique_only": true, "skip_proxy": true, "test": true, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}", {
method: "PATCH",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"search_query": "string", "query": "string", "name": "string", "max_results": 0, "extract_reviews": true, "extract_photos": true, "lang": "string", "store_images": true, "validate_phones": true, "fuzziq_enabled": true, "fuzziq_unique_only": true, "skip_proxy": true, "test": true, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"search_query": "string", "query": "string", "name": "string", "max_results": 0, "extract_reviews": true, "extract_photos": true, "lang": "string", "store_images": true, "validate_phones": true, "fuzziq_enabled": true, "fuzziq_unique_only": true, "skip_proxy": true, "test": true, "workflow": {"spidersite": {"enabled": false, "mode": {}, "max_pages": 25, "crawl_strategy": "bestfirst", "target_pages": ["contact", "about", "team", "news", "blog"], "enable_spa": true, "spa_timeout": 30, "extract_team": false, "extract_company_info": false, "extract_pain_points": false, "product_description": {}, "icp_description": {}, "compendium": {}, "timeout": 30}, "spiderverify": {"enabled": false, "check_gravatar": false, "check_dnsbl": false, "smtp_timeout_secs": 45, "max_emails_per_business": 10}, "vayapin": {"enabled": false}, "social_media_enrichment": {"enabled": true}, "smartlead": {"enabled": false, "connection_id": {}, "remote_campaign_id": {}, "remote_campaign_name": {}, "limit": {}, "only_with_vayapin_seo": false, "only_with_vayapin_pin": false, "field_map": {}}, "filter_social_media": true, "filter_review_sites": true, "filter_directories": true, "filter_maps": true}}`)
req, _ := http.NewRequest("PATCH", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Delete Campaign
Delete a campaign and all related data.
Requirements:
- Campaign must be stopped (no active jobs)
- User must own the campaign
Cascade deletes:
- campaign_locations (auto via FK)
- campaign_workflow_jobs (auto via FK)
- orchestrated_campaign_runs (manual)
- location_worker_runs (manual)
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true |
Try it
Examples
cURL
curl -X DELETE 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.delete(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}", {
method: "DELETE",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Campaign Stage Progress
Return per-stage campaign progress (Maps / Site / Verify / Vayapin).
Replaces the misleading single "0/N 0%" bar with location-level completed/active/queued/failed counts per pipeline stage, plus a velocity-based ETA. Stage list is derived from the campaign's workflow_config — Site/Verify/Vayapin only appear when their config block has enabled=True.
Cached in Redis for 30s (chrome polls every 15s while active).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stage-progress' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stage-progress",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stage-progress", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stage-progress", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
List Campaign Jobs
List jobs for a specific campaign with pagination.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
page | query | integer | false | |
page_size | query | integer | false | |
status | query | any | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Submit Next Job
Submit the next pending job in the campaign.
Two safety properties this endpoint enforces:
- Cross-tenant authorization (Bug #2-bis fix). Without this check, any authenticated
client_usercould call /next on any campaign by guessing its ID — the job would be billed to the caller's ownclient_idwhile writing into another tenant'sscraping_campaigns.workflow_*counters.can_access_campaignresolves the rightful owner.
- Tenant Bearer forging (Bug #2 fix). The campaign WindMill flow's sub-modules (SpiderMaps, SpiderSite, SpiderVerify, VayaPin) are strict-required since the §D1 audit-2 redeploy: an empty
api_tokenraisesValueError('api_token is required')rather than falling back tof/spideriq/api_token(which holds a stale workspace Bearer). We forge the Bearer from the campaign owner's stored credentials, not the caller's — super_admin impersonating VAYAPIN must dispatch as VAYAPIN, not as themselves.
Shared helper at app/services/tenant_bearer.py. Mirror of _resolve_tenant_bearer in app/api/v1/jobs/pipeline_flows.py.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/next' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/next",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/next", {
method: "POST",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/next", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Stop Campaign
Stop/pause a campaign.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stop' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stop",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stop", {
method: "POST",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/stop", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Continue Campaign
Resume a stopped campaign.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/continue' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/continue",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/continue", {
method: "POST",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/continue", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Job Results
Get results for a specific job in the campaign.
If wait=True, blocks until the job completes (up to 10 minutes).
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
job_id | path | string | true | |
wait | query | boolean | false | Wait for job completion |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs/{job_id}/results' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs/{job_id}/results",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs/{job_id}/results", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/jobs/{job_id}/results", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Export Campaign Results
Export all campaign results.
Exports all completed job results for a campaign in JSON or CSV format.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
format | query | string | false | Export format: json or csv |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/export' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/export",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/export", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/export", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
List Campaign Runs
Get Inngest workflow runs for a campaign.
Returns tracked runs from the orchestrated_campaign_runs table, showing run status, timing, and step counts.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
page | query | integer | false | |
page_size | query | integer | false |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Campaign Run Detail
Get detailed information about a specific campaign run.
Returns run details including step-level information for waterfall visualization.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
run_id | path | integer | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs/{run_id}' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs/{run_id}",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs/{run_id}", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/runs/{run_id}", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Get Location Worker Runs
Get worker runs for a specific campaign location.
Returns SpiderMaps, SpiderSite, and SpiderVerify runs with timing and results. Enables per-job visibility in campaign detail UI.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
location_id | path | integer | true |
Try it
Examples
cURL
curl -X GET 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/runs' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.get(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/runs",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/runs", {
method: "GET",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("GET", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/runs", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Retry Location
Retry a failed or completed location. Always auto-submits.
- retry_mode="full": Re-run entire workflow from SpiderMaps
- retry_mode="site": Keep Maps results, re-run SpiderSite + SpiderVerify
- retry_mode="verify": Keep Site results, re-run SpiderVerify only
Max 3 retries per location. Returns 400 if limit exceeded.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
location_id | path | integer | true |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/retry' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"retry_mode": "full"
}'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/retry",
headers={"Authorization": "Bearer <token>", "Content-Type": "application/json"},
json={"retry_mode": "full"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/retry", {
method: "POST",
headers: { "Authorization": "Bearer <token>", "Content-Type": "application/json" },
body: JSON.stringify({"retry_mode": "full"})
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
"strings"
)
func main() {
body := strings.NewReader(`{"retry_mode": "full"}`)
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/retry", body)
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Reset Stuck Location
Reset a location stuck in 'submitted' (processing) state.
- mark_as="failed": Mark as failed (default)
- mark_as="pending": Reset to pending for re-submission
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
location_id | path | integer | true | |
mark_as | query | string | false |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/reset' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/reset",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/reset", {
method: "POST",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/locations/{location_id}/reset", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |
Bulk Retry Failed
Retry all failed locations in the campaign (up to max_locations).
Only retries locations that haven't exceeded the max retry limit (3). Returns list of location IDs that were reset and re-submitted.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id | path | string | true | |
max_locations | query | integer | false |
Try it
Examples
cURL
curl -X POST 'https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/retry-failed' \
-H 'Authorization: Bearer <token>'Python
import httpx
resp = httpx.post(
"https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/retry-failed",
headers={"Authorization": "Bearer <token>"},
)
resp.raise_for_status()
print(resp.json())JavaScript
const resp = await fetch("https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/retry-failed", {
method: "POST",
headers: { "Authorization": "Bearer <token>" }
});
const data = await resp.json();
console.log(data);Go
package main
import (
"net/http"
)
func main() {
req, _ := http.NewRequest("POST", "https://spideriq.ai/api/v1/dashboard/client/campaigns/{campaign_id}/retry-failed", nil)
req.Header.Set("Authorization", "Bearer <token>")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
}Responses
| Status | Description |
|---|---|
200 | Successful Response |
422 | Validation Error |