# uprank — SEO, run by your agent uprank does the SEO work: keyword research, drafting, publishing to your CMS, rank tracking, AI-visibility tracking, and real backlink outreach. Every capability is operable by an agent over MCP and REST — your agent owns the strategy (which topics, refresh vs. write, what "good" means) and uprank is the machinery it fires. The full research → draft → approve → publish → track → links loop is live today. Honest by design: real prospecting and personalized outreach with a human approval gate, never a customer-to-customer link exchange. Publishing is human-gated by default; the agent earns autonomy per site. ## Authentication One API key unlocks everything: Authorization: Bearer up_live_... Create keys in Settings → API keys. The full key is shown once, at creation. The same key authenticates MCP and REST. A shared per-key rate limit applies to both surfaces; over the limit returns 429 with a Retry-After header. ## MCP (recommended for agents) Endpoint: https://uprank.tech/api/mcp (streamable HTTP) Connect with Claude Code: claude mcp add --transport http uprank https://uprank.tech/api/mcp \ --header "Authorization: Bearer up_live_..." Call get_site_overview first to orient. Tools cover the whole loop: sites (list_sites, create_site, get_site, update_site); research (research_keywords, get_keyword_clusters, analyze_serp, suggest_topics, track_keywords / untrack_keywords); content (generate_outline, generate_article, list_articles, get_article, update_article, get_quality_report, get_internal_link_opportunities, apply_internal_links); publishing (list_integrations, publish_article, schedule_articles, list_publications, retry_publish); tracking (get_rankings, get_rank_history, check_ranks, get_search_performance, inspect_url, detect_cannibalization, get_ai_visibility, set_ai_prompts [Pro]); link building (create_link_campaign, hunt_prospects, list_prospects, approve_prospects, list_handoffs, list_placements, get_campaign_status, pause_campaign, set_pitch_rules, list_inbound_pitches); and events (get_events, create_webhook, list_webhooks, delete_webhook). Call tools/list for the authoritative set. ## REST API Base: https://uprank.tech/api/v1 — same bearer key. GET /api/v1/whoami the workspace this key belongs to GET /api/v1/usage usage_ledger rollup (last 30 days) GET /api/v1/plan plan, caps, and live usage (budgeting) GET /api/v1/sites list sites POST /api/v1/sites create a site {"domain":"example.com"} GET /api/v1/sites/:id get one site PATCH /api/v1/sites/:id update autoPublish / agentCanPublish / language / brandVoice POST /api/v1/sites/:id/research seed → clustered keywords {"seed","limit"?} GET /api/v1/sites/:id/clusters keyword clusters for the site GET /api/v1/sites/:id/topics prioritized topics to write next GET /api/v1/sites/:id/keywords list keywords (?tracked=true|false) POST /api/v1/sites/:id/keywords track {"keywordIds"|"keywords":[…]} (plan-capped) DELETE /api/v1/sites/:id/keywords untrack {"keywordIds"|"keywords":[…]} POST /api/v1/serp/analyze SERP brief for a keyword {"keyword","location"?,"device"?} POST /api/v1/sites/:id/outline generate an outline {"keyword":"..."} GET /api/v1/sites/:id/articles list a site's articles (?state= to filter) POST /api/v1/sites/:id/articles draft {"keyword"|"brief"|"articleId":…} GET /api/v1/articles list articles across sites (?siteId=&state=) GET /api/v1/articles/:id get one article (markdown, html, outline) PATCH /api/v1/articles/:id edit title / markdown / meta / state GET /api/v1/articles/:id/quality deterministic quality report (score) POST /api/v1/articles/:id/quality recompute the quality report GET /api/v1/sites/:id/internal-links find internal-link opportunities POST /api/v1/articles/:id/internal-links apply links {"all":true|"linkIds":[…]} GET /api/v1/articles/:id/content portable content payload (pull) GET /api/v1/sites/:id/integrations list publishing integrations POST /api/v1/sites/:id/integrations connect one {"kind","name","config"?} (agent may connect kind "webhook"; CMS targets + Search Console are human-only) Webhook integrations sign their deliveries: supply your own secret as credentials.secret, or omit it and uprank generates one — returned once as "signingSecret" in the create response. DELETE /api/v1/integrations/:id disconnect an integration POST /api/v1/articles/:id/publish publish {"integrationId","mode"?,"publishAt"?} GET /api/v1/articles/:id/publications publication status per integration GET /api/v1/sites/:id/rankings tracked keywords + positions + deltas POST /api/v1/sites/:id/check-ranks force a check {"keywordId"?,"deep"?} GET /api/v1/keywords/:id/history one keyword's snapshot timeline (?days=) GET /api/v1/sites/:id/search-performance GSC clicks/impressions/queries (?days=) POST /api/v1/sites/:id/inspect-url indexation status {"url":"https://…"} GET /api/v1/sites/:id/cannibalization queries where 2+ pages compete GET /api/v1/sites/:id/ai-visibility LLM brand mentions [Pro] POST /api/v1/sites/:id/ai-visibility set tracked prompts [Pro] POST /api/v1/link-campaigns start a link campaign (the brief) GET /api/v1/link-campaigns/:id campaign funnel + brief POST /api/v1/link-campaigns/:id/pause pause (or {"resume":true}) POST /api/v1/link-campaigns/:id/hunt run prospecting for the campaign GET /api/v1/prospects prospect pool (?campaignId= to scope) POST /api/v1/contacts/approve approve contacts {"contactIds":[…]} GET /api/v1/handoffs contacts waiting on a human GET /api/v1/placements won/in-flight links (?status=) GET /api/v1/pitches inbound guest-post pitches GET /api/v1/sites/:id/pitch-rules guest-post inbox rules PUT /api/v1/sites/:id/pitch-rules set rules {niches,acceptPaid,…} GET /api/v1/events the event feed (?siteId=&type=&since=&limit=) GET /api/v1/webhooks list webhook endpoints POST /api/v1/webhooks subscribe {"url":"https://…","events":[…]} DELETE /api/v1/webhooks/:id delete a webhook endpoint ## Webhooks (events out) Subscribe an HTTPS endpoint to the event feed and uprank POSTs each new event as a signed {"events":[…]} batch — headers X-Uprank-Signature (sha256=hex HMAC of `${timestamp}.${body}`) and X-Uprank-Timestamp. Filter by event type ("rank.moved") or namespace prefix ("rank."), or omit events for all. The signing secret is returned once at creation. Delivery retries every minute until it succeeds; an endpoint auto-disables after 10 consecutive failures. ## Events The event vocabulary (poll GET /api/v1/events or subscribe a webhook): article.published, article.updated, article.publish_failed rank.moved, page.deindexed, content.decaying ai_overview.gained, ai_overview.lost ai_visibility.gained, ai_visibility.lost link.placed, link.lost, link.recovered pitch.received, digest.sent ## CLI The `uprank` CLI ships in this repo under cli/ — a zero-dependency Node tool (there is no npm package; install from source). `uprank pull --site --dir [--format md|json]` writes your published articles as markdown-with-frontmatter (or JSON) files — the content path for Next.js/Astro/Hugo/any static site. Env: UPRANK_API_KEY + UPRANK_API_URL. ## Approval gates Publishing is human-gated by default (per site): - autoPublish off (default): an approved draft still waits for a human. - agentCanPublish off (default): the agent can't approve at all. A "pending approval" outcome is success, not failure. Flip these with update_site (or PATCH /api/v1/sites/:id) only when the user asks for more autonomy.