Skip to main content
POST
SEO research
Every action returns normalized output. The Provider’s native output is not repeated there; it stays on the Run and is readable with Get Run. List actions expose output.items[] with fixed fields per row; overview actions expose fixed top-level fields. A value the selected Provider does not report is null; Glasser does not convert or fill in values. Money is always USD (cpc_usd, organic_traffic_value_usd). volume, traffic and cpc_usd are the answering Provider’s own estimates. Compare them only within one Provider (runs[].provider), not across Providers. Read result_status separately from status: success, no_result, error or pending. An empty but valid answer is no_result and keeps the action’s shape: items is [], or every top-level field is null. error with error.code means the Provider output could not be delivered. charge_usd totals this response’s runs, including charged empty results, and is null until all Runs settle. With provider: auto, fallback can create multiple Runs, each listed in runs[] with its own charge. For a pending crawl (site_audit, HTTP 202), follow the authenticated result_url. Get Run remains native and reports an individual charge. See Provider selection and charges.

Output by action

Every field is present on every row; a value the Provider does not report is null. Fields follow the field conventions: money ends in _usd, timestamps end in _at (ISO 8601 UTC), and domain is a bare hostname without www. or a port. Authority scores keep each Provider’s own metric and name and are never converted: ahrefs_domain_rating (Ahrefs Domain Rating, 0–100, may have decimals), semrush_authority_score (Semrush Authority Score, 0–100), dataforseo_rank (DataForSEO rank, 0–1000) and serpstat_domain_rank (Serpstat Domain Rank, 0–100). Keyword difficulty is split the same way: semrush_keyword_difficulty, serpstat_keyword_difficulty, dataforseo_keyword_difficulty and ahrefs_keyword_difficulty are each 0–100 on the Provider’s own model, so the same keyword can score very differently between them. dataforseo_onpage_score is DataForSEO’s own page score. Only the field of the Provider that answered is filled; the others are null. position is the organic position: 1 is the first organic result, and SERP features such as ads or answer boxes are not counted. keyword_gap rows differ by Provider: Semrush returns keywords any of the domains ranks for (a union), while DataForSEO returns keywords the competitor ranks for and you do not. ai_visibility reports two different metrics: Ahrefs counts citations of the domain’s pages in AI answers, DataForSEO counts LLM mentions of the domain. Each Provider fills only its own fields, and there is no cross-Provider total. Semrush first_seen_at carries no time zone (Semrush does not state one), so it has no Z suffix.

Headers

idempotency-key
string
required

Generate a unique value for each intended execution (a UUID is recommended). Retry with the same key and execution parameters to retrieve the original Run without a second charge. Changing execution parameters with the same key returns 409; changing task_id or metadata does not update the original Run.

Minimum string length: 1

Body

application/json
action
enum<string> | null

Default: keyword_overview.

  • keyword_overview: supply one or more keywords.
  • keyword_ideas or serp: supply exactly one keyword in keywords.
  • site_audit: supply domain; limit is the number of pages to crawl (default 20, at most 100). The crawl runs asynchronously.
  • keyword_gap and backlink_gap: supply domain and one to four competitors.
  • page_audit: supply url (one page).
  • visibility_history: supply domain; limit is the number of months (default 12, at most 24).
  • All other actions: supply domain. organic_competitors finds domains ranking for the same keywords; ai_visibility: AI-answer visibility in the answering Provider's own metric (Ahrefs: citations of the domain's pages; DataForSEO: LLM mentions of the domain); ai_citations: pages most cited in AI answers that mention the domain, from any site.
  • keyword_gap rows differ by Provider: Semrush returns keywords any of the domains ranks for (union); DataForSEO returns keywords the competitor ranks for and you do not.
Available options:
keyword_overview,
keyword_ideas,
serp,
domain_overview,
ranked_keywords,
organic_competitors,
backlinks_overview,
backlinks,
referring_domains,
domain_rating,
site_audit,
ai_visibility,
keyword_gap,
backlink_gap,
page_audit,
visibility_history,
ai_citations
provider
enum<string> | null

Default auto: select the first eligible Provider in Glasser's preference order. A named Provider must support the request and be allowed by your Key; it does not fall back to another Provider. Available values are listed below.

Available options:
auto,
semrush,
serpstat,
dataforseo,
ahrefs,
serper
keywords
string[] | null
Required array length: 1 - 20 elements
Required string length: 1 - 200
domain
string | null

A website domain such as stripe.com. A full URL is accepted and reduced to its host.

Required string length: 3 - 253
competitors
string[] | null

Competitor domains for keyword_gap and backlink_gap, one to four. Full URLs are reduced to their host.

Required array length: 1 - 4 elements

A website domain such as stripe.com. A full URL is accepted and reduced to its host.

Required string length: 3 - 253
url
string | null

One page URL for page_audit, such as https://stripe.com/pricing.

Required string length: 1 - 2048
country
string | null

Country as a two-letter ISO code or a country name, e.g. us, gb, de, Germany. Default us. An unsupported country is refused with the supported list.

Required string length: 2 - 60
limit
integer | null

Rows to return. Keep it small: the routed Endpoint's charge rule may read it. Each capability caps it further.

Required range: 1 <= x <= 100
task_id
string | null

Group related Runs, including automatic fallback, under one Task. Reuse a stable string and filter the Runs list by task to retrieve them.

metadata

Optional tracking fields, returned on the Run and available as filters. They never go to the Provider or affect routing, Price, or idempotency.

  • Up to 20 keys: lowercase letters, digits, and underscores; start with a letter; at most 40 characters.
  • Values: strings of 1–500 characters.
  • user_id: your End user's opaque ID, never their email address or name.

Invalid entries are dropped whole, not truncated. The request continues, and the Run returns the fields that were stored.

Response

Success

id
string
required
run_url
string
required

Open this Run in the console. Requires Workspace membership.

provider
string
required
Pattern: ^[a-z0-9][a-z0-9-]*$
endpoint
string
required
Pattern: ^\/.+$
endpoint_version
integer
required
status
enum<string>
required

QUEUED or RUNNING: still in progress. COMPLETED: a Provider response is available, including non-2xx responses. FAILED: read failure. STOPPED: stopped before dispatch. Read charge_usd separately from status.

Available options:
QUEUED,
RUNNING,
COMPLETED,
FAILED,
STOPPED
failure
object | null
required

Why the Run failed. Non-null only when status is FAILED.

input
object
required
output
object
required

Normalized fields per action. The Provider's native output is not repeated here; it stays on the Run (GET /v1/runs/:id). Values a Provider does not report are null. Money is USD. Authority scores keep the answering Provider's own metric and name and are never converted: ahrefs_domain_rating (Ahrefs Domain Rating, 0–100), semrush_authority_score (Semrush Authority Score, 0–100), dataforseo_rank (DataForSEO rank, 0–1000), serpstat_domain_rank (Serpstat Domain Rank, 0–100). Keyword difficulty is split the same way (semrush_keyword_difficulty, serpstat_keyword_difficulty, dataforseo_keyword_difficulty, ahrefs_keyword_difficulty, each 0–100 on its own model). Only the field of the Provider that answered is filled; the others are null. volume, traffic and cpc are the answering Provider's estimates; compare them only within one Provider (runs[].provider). An empty answer (result_status no_result) keeps the action's shape: items is [], or every field is null.

  • keyword_overview: items[]: keyword, volume, cpc_usd, semrush_keyword_difficulty, serpstat_keyword_difficulty, dataforseo_keyword_difficulty, ahrefs_keyword_difficulty, intent
  • keyword_ideas: items[]: same row as keyword_overview
  • serp: items[]: position (organic position: 1 = first organic result; SERP features not counted), url, domain, title, snippet (organic results only)
  • domain_overview: organic_keywords, organic_traffic, organic_traffic_value_usd, paid_keywords, paid_traffic
  • ranked_keywords: items[]: keyword, position (organic position: 1 = first organic result; SERP features not counted), url, volume, cpc_usd, traffic
  • organic_competitors: items[]: domain, common_keywords, organic_keywords (the competitor's total), organic_traffic (the target domain and its subdomains are left out)
  • backlinks_overview: backlinks, referring_domains, semrush_authority_score, dataforseo_rank, serpstat_domain_rank, dofollow_backlinks, nofollow_backlinks
  • backlinks: items[]: source_url, target_url, anchor, source_ahrefs_domain_rating, source_semrush_authority_score, source_dataforseo_rank, dofollow, first_seen_at (ISO 8601 UTC; Semrush: zone not stated, no Z suffix). One row per link from every Provider
  • referring_domains: items[]: domain, ahrefs_domain_rating, semrush_authority_score, dataforseo_rank, backlinks, dofollow_backlinks, first_seen_at (ISO 8601 UTC; Semrush: zone not stated, no Z suffix)
  • domain_rating: ahrefs_domain_rating
  • site_audit: dataforseo_task_id (input to DataForSEO's OnPage report endpoints), crawl_progress, crawl_stop_reason (DataForSEO's vocabulary), pages_crawled, dataforseo_onpage_score, broken_links, non_indexable, duplicate_title, duplicate_description, duplicate_content
  • keyword_gap: items[]: keyword, volume, cpc_usd, semrush_keyword_difficulty, dataforseo_keyword_difficulty, positions {domain: organic position; null = not in the top 100}, keyed by the domains sent. Semrush rows are keywords any of the domains ranks for (union); DataForSEO rows are keywords the competitor ranks for and you do not
  • backlink_gap: items[]: domain, dataforseo_rank, backlinks_per_target {competitor domain: count}
  • page_audit: url, status_code, title, description, canonical, dataforseo_onpage_score, internal_links, external_links
  • visibility_history: items[]: month, organic_keywords, organic_traffic, organic_traffic_value_usd, paid_keywords, paid_traffic
  • ai_citations: items[]: url, platform, mentions, ai_search_volume, is_target_domain (pages most cited in AI answers that mention the domain, from any site)
  • ai_visibility: ahrefs_ai_citations, ahrefs_ai_cited_pages, ahrefs_ai_citations_by_platform {platform: citations}, dataforseo_ai_mentions_by_platform {platform: mentions}, dataforseo_ai_search_volume_by_platform {platform: AI search volume}. Each Provider fills only its own fields; no cross-Provider total
provider_response
object | null
required

Non-null only when status is COMPLETED.

  • For 2xx responses, output contains Provider-native JSON (any shape), or null for an empty body.
  • For non-2xx responses, error contains the Provider's error body and output is null.

Sensitive fields are removed from both bodies.

charge_usd
string | null
required

Total charge of runs in this Solution response. Null until all listed Runs settle. Each Run retains its own charge; failures can also be charged.

Pattern: ^(0|[1-9]\d*)\.(\d{2}|\d{2}\d{0,3}[1-9])$
charge_basis
object | null
required

Single-Run charge basis, or null for a multi-Run total. Read runs[].charge_basis for each charge.

stoppable
boolean
required

Whether a stop request can currently be accepted. This does not guarantee that the Run can stop before dispatch.

stop_requested_at
string<date-time> | null
required

When a stop was requested. The Run can still continue if dispatch had already started.

created_at
string<date-time>
required

ISO-8601 UTC timestamp

started_at
string<date-time> | null
required

ISO-8601 UTC timestamp

completed_at
string<date-time> | null
required

ISO-8601 UTC timestamp

task_id
string | null
required
metadata
object
required

Your stored tracking fields. Use them to filter Runs. They never go to the Provider or affect routing, Price, or idempotency.

  • Up to 20 keys: lowercase letters, digits, and underscores; start with a letter; at most 40 characters.
  • Values: strings of 1–500 characters.
  • user_id: your End user's opaque ID, never their email address or name.
action
enum<string>
required
Available options:
keyword_overview,
keyword_ideas,
serp,
domain_overview,
ranked_keywords,
organic_competitors,
backlinks_overview,
backlinks,
referring_domains,
domain_rating,
site_audit,
ai_visibility,
keyword_gap,
backlink_gap,
page_audit,
visibility_history,
ai_citations
result_status
enum<string>
required

Business delivery status, independent of the final Run lifecycle in status. no_result is an empty but valid answer; error means the Provider output could not be delivered.

Available options:
success,
no_result,
error,
pending
error
object | null
required
runs
object[]
required
result_url
string
required

Authenticated, read-only URL path for polling this normalized result and total charge. Use with the API origin. Does not create Runs or resume fallback. GET /v1/runs/:id still returns the native, individual Run.