SV CLI
An open-source command-line client for agentic SEO and GEO workflows. Humans use friendly commands and aliases; scripts and AI agents use strict enum IDs and raw JSON. All 16 SV API endpoints available from your terminal.
01Install
sv. No other dependencies needed for basic use.pip install sv-cli
# Local dev setup
git clone https://github.com/seovendorco/sv-cli.git
cd sv-cli
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e '.[dev]'
sv --help02API key setup
--api-key in shared shells — shell history may store the value. Debug output automatically masks keys.Config is stored in ~/.sv/config.json. The legacy path ~/.seovendor/config.json is still read as a migration fallback. New saves always go to ~/.sv.
Multi-agency profiles
Each profile stores a separate API key. Switch between agency accounts with a single flag.
sv profile create agency-a
sv --profile agency-a auth set
sv profile use agency-a
sv profile list
sv profile delete agency-a# Recommended: store once, use everywhere
sv auth set
sv auth status
# Or set the environment variable (preferred for CI and agents)
export SV_API_KEY="your-key-here"
# CI / non-interactive
sv seogpt generate --type 18 --keyword "white label seo" \
--strict --format json --non-interactive
# Key resolution order:
# 1. --api-key flag (avoid in shared shells — history may store it)
# 2. SV_API_KEY environment variable
# 3. Stored profile: sv auth set
# 4. Interactive prompt (when allowed)
# Legacy: SEOVENDOR_API_KEY still accepted03Quick start
Every API tool is available as a CLI command. These examples cover the most common operations across all 16 endpoints. Common enum IDs: seogpt --type 18 = Meta Description, --type 8 = Page Title, seo-image --type 33 = Blog Header Image, seogpt2 --type 0 = On-Page Blog Article. Always verify with sv options TOOL type before use.
# Keyword research
sv keywords research --keyword "white label seo"
# Generate a meta description (type 18)
sv meta --keyword "white label seo" --url https://seovendor.co
# Generate a title (type 8)
sv title --keyword "white label seo" --url https://seovendor.co
# GEO audit (async — --wait polls until complete)
sv geo-audit create-task \
--url https://seovendor.co \
--keyword "seo agency,white label seo" --wait
# Generate an SEO image (type 33 = Blog Header Image)
sv image generate --keyword "white label seo" --type 33
# Top 10 competing URLs for a keyword
sv top-competitors analyze --keyword "white label seo"
# Search marketplace services
sv marketplace-services search \
--search "seo audit" --price 500 --category SEO
# Content quality check (HCU / E-E-A-T)
sv content-quality analyze \
--keyword "white label seo" --url https://seovendor.co04Tool reference
Every SV API endpoint maps to a CLI command. Use exact command names in scripts — aliases are human shortcuts only. Async tools return a task_id; use --wait or poll manually.
| sv command | Aliases | Default action | Required flags | All actions | API page |
|---|---|---|---|---|---|
| seogpt | seo-gpt | generate | --keyword --type | generate, raw | seogpt |
| seogpt2 | seo-gpt2 | create-task async | --keyword (=Topic) | create-task, get-task-status, get-result, raw | seogpt2 |
| content-transformer | transform | rewrite | --text | rewrite, raw | content-transformer |
| seo-image | image | generate | --keyword | generate, raw | seo-image |
| better-keywords | keywords | research | --keyword | research, filter, raw | better-keywords |
| insight-igniter | insights | entities | --url | entities, raw | insight-igniter |
| topical-authority | topical | topics | --keyword | topics, content, raw | topical-authority |
| core-analysis | core | analyze | (none) | analyze, raw | core-analysis |
| preliminary-audit | prelim-audit | analyze | --url | analyze, raw | preliminaryaudit |
| geo-audit | geogpt-auditaudit | create-task async | --url --keyword | create-task, get-task-status, get-result, raw | geogptaudit |
| seogpt-compare | compare | create-task async | --url --keyword | create-task, get-task-status, get-result, raw | seogptcompare |
| seo-mapping | mapping | create-task async | --url --keyword | create-task, get-task-status, get-result, raw | seogptmapping |
| ranklens | — | rank | --keyword --url | rank, competitors, raw | ranklens |
| content-quality | qualityhcu-qualityeeat-quality | analyze | --keyword --url | analyze, raw | content-quality |
| top-competitors | competitors | analyze | --keyword | analyze, raw | top-competitors |
| marketplace-services | marketplaceservices | search | --search | search, raw | marketplace-services |
05Enum resolution
--type, --language, --engine, --theme, etc. Run sv options TOOL FIELD first. In agent/script context use --strict --no-fuzzy to require exact ID or slug and prevent unintended matches.Discovery commands
# Discover all option fields for a tool
sv options seogpt
# List all values for a specific field
sv options seogpt type
# Filter by keyword
sv options seogpt type --search meta
# Tool-specific shorthand (where available)
sv seogpt types
sv seogpt types --search meta
sv seogpt languages
sv seogpt engines
sv image types
sv image themes --search wild
sv seogpt2 types
sv seogpt2 lengths
sv seogpt2 tones
sv seogpt2 engines
sv geo-audit languages
sv ranklens engines
sv topical-authority modes
sv marketplace-services series
sv marketplace-services categoriesResolution & agent-safe mode
# All of these resolve to Meta Description (id 18):
sv seogpt generate --type 18
sv seogpt generate --type meta-description
sv seogpt generate --type "Meta Description"
sv seogpt generate --type "meta desc"
# Options output columns — use id or slug with --strict:
# label slug id
# ---------------- ---------------- ---
# Meta Description meta-description 18
# Meta Keywords meta-keywords 180
# Agent-safe: require exact ID or slug, no guessing
sv seogpt generate \
--type 18 \
--keyword "white label seo" \
--strict --no-fuzzy --non-interactive --format json06Async tasks
--wait for the simplest flow; poll manually for long-running jobs or when you need to store the task_id between steps.Pattern 1 — --wait (simplest)
# --wait polls automatically (default timeout 600s)
sv geo-audit create-task \
--url https://seovendor.co \
--keyword "seo agency,white label seo" \
--wait --strict --no-fuzzy --non-interactive --format json
# Override timeout and poll interval
sv seogpt2 create-task \
--keyword "White Label SEO for Agencies" --type 0 \
--wait --timeout 300 --poll-interval 10 \
--strict --no-fuzzy --non-interactive --format jsonPattern 2 — Manual 3-step poll
# Step 1 — create task
sv geo-audit create-task \
--url https://seovendor.co --keyword "seo agency" \
--non-interactive --format json
# → parse: response["data"]["task_id"]
# Step 2 — poll status (repeat until done)
sv --format json task status TASK_ID --tool geo-audit
# done when: status is "done|complete|completed|success|finished|ready"
# Step 3 — get result
sv --format json task result TASK_ID --tool geo-audit
# Direct tool polling (same result)
sv geo-audit get-task-status --task_id TASK_ID --format json
sv geo-audit get-result --task_id TASK_ID --format json
# --tool required if task not created in current session
# (not found in ~/.sv/tasks.json)07Response shapes
All responses use the standard envelope (success, application, action, data, meta, error). The data field shape varies by endpoint type.
| Shape | Returned by | Parse |
|---|---|---|
| Content | seogpt generate, content-transformer rewrite, sv meta, sv title | response["data"]["text"] |
| List | better-keywords research, top-competitors analyze, marketplace-services search, topical-authority topics | response["data"] — array of objects |
| Async created | geo-audit create-task, seogpt2 create-task, seogpt-compare create-task, seo-mapping create-task | response["data"]["task_id"] |
| Task status | any get-task-status | response["data"]["status"] |
| Audit / analysis | core-analysis, preliminary-audit, content-quality, ranklens | response["data"] — nested object |
// Content
{ "data": { "text": "generated content here" } }
// List
{ "data": [ { "keyword": "...", "volume": 1000 }, ... ] }
// Async task created
{ "data": { "task_id": "wFEGe...", "status": "pending",
"stage": "queued", "percent_complete": 1 } }
// Task status
{ "data": { "task_id": "...", "status": "processing",
"percent_complete": 75 } }
// Done when status is one of:
// "done" | "complete" | "completed" | "success" | "finished" | "ready"
// Audit / analysis
{ "data": { ... nested analysis object ... } }08Critical field exceptions
A handful of fields do not map to standard CLI flags. Get these wrong and the call fails silently or returns unexpected results.
seogpt2 — --keyword maps to Topic, not kw
seogpt2’s required field is Topic (an article title or subject). The CLI maps --keyword to Topic internally — no other flag does this.
seogpt — --contenttype is an alias for --type
Both flags select the content type integer. Use whichever is clearer; --type 18 and --contenttype meta-description are equivalent.
# CORRECT — --keyword sends value as the "Topic" API field
sv seogpt2 create-task \
--keyword "White Label SEO for Agencies" \
--type 0 --wait \
--strict --no-fuzzy --non-interactive --format json
# --contenttype is an alias for --type on seogpt
sv seogpt generate \
--keyword "white label seo" \
--contenttype meta-description \
--strict --no-fuzzy --non-interactive --format jsonbetter-keywords filter — requires data array
The filter action AI-filters a keyword list for relevance. No CLI flag maps to the data field — you must pass the keyword array from a prior research call via a raw JSON call.
# better-keywords filter requires a data array from a prior research call.
# No CLI flag maps to data — must use a raw call.
# Step 1 — research to get keyword array
sv keywords research --keyword "white label seo" \
--non-interactive --format json
# → parse response["data"] (array of keyword objects)
# Step 2 — filter using that array via raw call
sv --format json call better-keywords \
--json '{"action":"filter","kw":"white label seo","data":[{"keyword":"...","volume":1000}]}'ranklens competitors — requires mgptid
The competitors action needs the mgptid returned by a prior rank call. No CLI flag exists for this field — use a raw call.
# ranklens competitors action requires mgptid from a prior rank response.
# No CLI flag maps to mgptid — must use a raw call.
# Step 1 — get MGPTID from rank response
sv ranklens rank --keyword "white label seo" \
--url https://seovendor.co --format json
# → parse response["data"]["MGPTID"]
# Step 2 — pass MGPTID via raw call
sv --format json call ranklens \
--json '{"action":"competitors","mgptid":"MGPTID_VALUE","web":"https://seovendor.co","kw":"white label seo"}'09Output formats
Six output formats. --format placement differs between tool commands and global commands (sv call, sv task, sv TOOL raw) — for those, --format must come before the subcommand.
| Response type | Recommended format |
|---|---|
| list results (keywords, competitors, services) | table, csv |
| content / articles / generated text | text, markdown |
| audit / analysis / nested data | json, markdown |
| async task ID responses | pretty (default) |
| any response | json (always safe) |
# --format anywhere on tool commands
sv seogpt generate --keyword "white label seo" --type 18 --format json
# --format MUST come BEFORE sv call / sv task / sv TOOL raw
sv --format json call seogpt --json '{"action":"generate","kw":"white label seo","type":18}'
sv --format json task status TASK_ID
sv --format json task result TASK_ID
sv --format json seogpt raw --json '{"action":"generate","kw":"white label seo","type":18}'
# Save output to file
sv keywords research --keyword "white label seo" --format csv --output keywords.csv
sv geo-audit create-task --url https://seovendor.co \
--keyword "seo agency" --wait --format markdown --output audit.md10Raw API calls
The call and per-tool raw subcommands pass a JSON payload directly to the API, injecting your key as k automatically. Only the endpoint URL is resolved from definitions; the rest of the payload is passed through unchanged. Use sv definitions show TOOL to inspect all API input fields before building raw payloads.
# Pass raw JSON directly — API key injected automatically
sv --format json call seogpt \
--json '{"action":"generate","kw":"white label seo","type":18}'
# From file
sv --format json call seogpt --file payload.json
# From stdin
cat payload.json | sv --format json call seogpt --stdin
# Per-tool raw subcommand (same behavior)
sv --format json seogpt raw \
--json '{"action":"generate","kw":"white label seo","type":18}'
# Inspect all input fields before building a payload
sv definitions show seogpt11Common errors
| Error message | Cause | Fix |
|---|---|---|
| Could not resolve --type "X" in strict mode | Value is not a valid slug or ID | Run sv options TOOL type → use the id or slug column |
| Could not resolve --type "X" | No match found at any resolution level | Run sv options TOOL type --search X to find the closest match |
| Topic is required | seogpt2 called without --keyword | Add --keyword "your topic title" |
| task_id is invalid | Task has expired on the server | Create a new task |
| No local tool mapping found for task | Task not in ~/.sv/tasks.json | Add --tool TOOL_NAME explicitly |
| API authentication failed: HTTP 401 | Bad or missing API key | Check SV_API_KEY environment variable |
| API rate limit exceeded | Too many requests | Wait and retry — add delay between calls |
| No such option: --format | --format placed after call/task/raw | Move --format before the subcommand: sv --format json call ... |
| Action must be rewrite | Wrong action for content-transformer | Only rewrite is supported |
| Data must be a JSON array | better-keywords filter called without data | Pass keyword array from prior research call via raw JSON (see section 08) |
12Quick reference
--strict --no-fuzzy --non-interactive --format json. Set SV_API_KEY as an environment variable — never use sv auth set in agent context (it’s interactive). Verify enum IDs with sv options TOOL FIELD before use; the IDs listed here are from the live API at time of writing.# All 16 tools — agent-safe one-liners
# Replace values as needed. Verify enum IDs with sv options first.
sv keywords research --keyword "white label seo" --strict --no-fuzzy --non-interactive --format json
sv --format json call better-keywords --json '{"action":"filter","kw":"white label seo","data":[{"keyword":"white label seo","volume":1000}]}'
sv content-transformer rewrite --text "SEO services for agencies" --keyword "white label seo" --strict --no-fuzzy --non-interactive --format json
sv core-analysis analyze --url https://example.com --keyword "white label seo" --strict --no-fuzzy --non-interactive --format json
sv geo-audit create-task --url https://example.com --keyword "white label seo" --wait --strict --no-fuzzy --non-interactive --format json
sv insight-igniter entities --url https://example.com --keyword "white label seo" --strict --no-fuzzy --non-interactive --format json
sv preliminary-audit analyze --url https://example.com --strict --no-fuzzy --non-interactive --format json
sv ranklens rank --keyword "white label seo" --url https://example.com --strict --no-fuzzy --non-interactive --format json
sv seo-image generate --keyword "white label seo" --type 33 --strict --no-fuzzy --non-interactive --format json
sv seogpt generate --keyword "white label seo" --type 18 --strict --no-fuzzy --non-interactive --format json
sv seogpt2 create-task --keyword "White Label SEO for Agencies" --type 0 --wait --strict --no-fuzzy --non-interactive --format json
sv seogpt-compare create-task --url https://example.com --keyword "white label seo" --wait --strict --no-fuzzy --non-interactive --format json
sv seo-mapping create-task --url https://example.com --keyword "white label seo" --wait --strict --no-fuzzy --non-interactive --format json
sv topical-authority topics --keyword "white label seo" --strict --no-fuzzy --non-interactive --format json
sv top-competitors analyze --keyword "white label seo" --strict --no-fuzzy --non-interactive --format json
sv marketplace-services search --search "seo audit" --category SEO --strict --no-fuzzy --non-interactive --format json
sv content-quality analyze --keyword "white label seo" --url https://example.com --strict --no-fuzzy --non-interactive --format json13Definitions cache
The CLI discovers available tools from the SV API root and fetches each tool’s definitions endpoint at runtime. Definitions are cached locally at ~/.sv/cache/definitions.json for speed and refreshed automatically after 24 hours.
sv definitions refresh # re-fetch from live API
sv definitions list # show all cached tools
sv definitions show seogpt # inspect a single tool’s full schema
sv definitions clear # wipe the cache
sv options list # all tools with option-set counts
# Cache location
~/.sv/cache/definitions.json
# Default behaviour:
# - Use local cache when present
# - Auto-refresh if cache > 24 hours old
# - Use stale cache with warning if refresh fails
# - Error clearly if no cache and API unreachable
# Legacy path still read as fallback
~/.seovendor/config.json → migrated to ~/.sv/config.jsonhttps://ai.seovendor.co/api · All requests are POST · JSON in, JSON out · © 2026 SEO Vendor. Built for agencies since 2004.