Open API

Use the Rankhog public REST API with OpenAPI, scoped auth, idempotency, and safe Reddit workflows.

Rankhog exposes the same paid agent capabilities through REST, MCP, and the CLI. Use REST when an external service or AI agent needs stable HTTP endpoints, OpenAPI schemas, idempotent writes, and status polling.

Base URL

RANKHOG_API_BASE_URL="https://api.rankhog.com"

The OpenAPI 3.1 document is available at:

curl https://api.rankhog.com/agent/openapi.json

See the generated API reference for every endpoint schema, response, auth mode, and example.

Authentication

REST supports three auth paths:

  • Organization API key: send Authorization: Bearer rhog_... or x-api-key.
  • CLI bearer token: minted by Better Auth device authorization.
  • OAuth bearer token: used by MCP and trusted OAuth clients.

API keys are organization automation credentials. Existing read only, read and draft (default), and automation presets retain their permissions. Growth operations adds product, strategy, and warm-up configuration to automation. Growth operations and safety resolutions additionally permits safety incidents, participation confirmations, and review-prompt changes. Existing keys are never upgraded automatically.

CapabilityRequired permission
Read growth state, diagnostics, jobs, and credit balancerankhog:read
Read the credit ledgercredits:read
Change product answers, market, or automation modeproduct:write
Configure Discovery and Radarstrategy:write
Configure/stop warm-upwarmup:write
Start warm-up executionwarmup:write and reddit:write:dangerous
Edit drafts and writing profilesreddit:draft:write
Resolve safety incidents or uncertain submissions; change review prompts or participation trust factsgrowth:safety:write, plus the operation's configuration permission
Execute/retry Reddit writes or enable autopilotreddit:write:dangerous, plus the operation's configuration/draft permission
Start conversations, post conversation messages and structured question answersconversation:write
Cancel, reschedule, or retry jobsjobs:write
Buy credits, change billing, delete data, manage team/security, change account protectionNot exposed

OAuth grants and API keys need the listed scopes. Human session actors retain their existing role checks. open_reddit_url remains human-authenticated. Get credit purchase link returns a Rankhog billing URL where an authorized human completes checkout; it never charges a card.

Mutations require an idempotencyKey. Reuse the key only with identical input: retries return the committed result, while different input returns agentic_idempotency_conflict. Permissions and product access are checked again before replay. Durable mutations are limited to 120 per actor and organization per hour; operation-specific limits can be lower.

The retired approve_reddit_draft and dangerously_submit_reddit_post endpoints have been removed. Use create_reddit_action followed by execute_reddit_action, or confirm_opportunity_action for a linked opportunity. update_opportunity_draft now also requires an idempotency key. Text posts use the Desktop post workflow after explicit dangerous execution authorization. A stored draft is not proof of a submission. Execution status reports humanNeeded when a person must finish or verify a step in Desktop; API keys cannot mark that human step done.

Every error uses one JSON envelope; see the error catalog for all codes, statuses, and remediation. Rate limited responses carry a Retry-After header.

Discovery and Radar

Read the current product-owned strategy:

curl "$RANKHOG_API_BASE_URL/agent/v1/strategy" \
  -H "Authorization: Bearer $RANKHOG_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "websiteId": "web_..."
  }'

Strategy mutations require strategy:write. Organization API keys may receive this explicit grant; human actors must also be organization owners or admins.

curl "$RANKHOG_API_BASE_URL/agent/v1/strategy/discovery/start" \
  -H "Authorization: Bearer $RANKHOG_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "websiteId": "web_...",
    "direction": "Find comparison demand",
    "idempotencyKey": "start-discovery-001"
  }'

Stopping Discovery uses /strategy/discovery/stop; running it now uses /strategy/discovery/run. Radar coverage is /strategy/radar/coverage, Radar control is /strategy/radar, and shared input replacement is /strategy/inputs. These endpoints change only the named lane or inputs.

Quickstart

List workspaces, create a Reddit action, execute it, then poll status.

export RANKHOG_API_BASE_URL="https://api.rankhog.com"
export RANKHOG_API_KEY="rhog_..."

curl "$RANKHOG_API_BASE_URL/agent/v1/workspaces" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{}'

Use the returned organization.id, website.id, and managedRedditAccount.id in later calls.

Read the workspace's current opportunities before creating or executing work:

curl "$RANKHOG_API_BASE_URL/agent/v1/opportunities" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "websiteId": "web_...",
    "managedRedditAccountId": "acct_...",
    "includeRecent": false,
    "limit": 50
  }'

Opportunity responses preserve evidence and may add evidenceSummary, timeZone, and nextTransitionAt. These read fields never approve or execute Reddit work.

Create a stored action. Every write needs an idempotency key.

curl "$RANKHOG_API_BASE_URL/agent/v1/reddit-actions" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "managedRedditAccountId": "acct_...",
    "actionType": "comment",
    "targetUrl": "https://www.reddit.com/r/SaaS/comments/examplepost/example/",
    "body": "We saw better activation after asking for one setup action instead of showing a long checklist.",
    "riskSummary": "Contextual reply with no link and no promotional claim.",
    "idempotencyKey": "action-comment-2026-06-17-001"
  }'

Execute the authorized action. The response is immediate and means the execution was queued, not necessarily submitted.

curl "$RANKHOG_API_BASE_URL/agent/v1/reddit-actions/execute" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "managedRedditAccountId": "acct_...",
    "plannedRedditActionId": "act_...",
    "acknowledgement": "I understand this can publish or change Reddit state from the user's Reddit account.",
    "requestedExecutorRedditAccountId": "ra_...",
    "idempotencyKey": "execute-action-2026-06-17-001"
  }'

Omit requestedExecutorRedditAccountId to let Rankhog pick the first ready product-granted Reddit account.

Queued response:

{
  "status": "queued",
  "executionId": "job_...",
  "jobId": "job_...",
  "plannedRedditActionId": "act_...",
  "statusUrl": "/agent/v1/reddit-action-executions/status?executionId=job_..."
}

Poll status:

curl "$RANKHOG_API_BASE_URL/agent/v1/reddit-action-executions/status" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "managedRedditAccountId": "acct_...",
    "executionId": "job_..."
  }'

Successful status includes the final Reddit location.

{
  "status": "succeeded",
  "executionId": "job_...",
  "plannedRedditActionId": "act_...",
  "redditAction": {
    "redditActionId": "ra_...",
    "permalink": "https://www.reddit.com/r/SaaS/comments/examplepost/example/examplecomment/",
    "currentUrl": "https://www.reddit.com/r/SaaS/comments/examplepost/example/examplecomment/",
    "submittedAt": "2026-06-17T11:46:08.000Z",
    "subreddit": "SaaS",
    "type": "comment"
  },
  "failure": null
}

Failed status includes machine-readable remediation.

{
  "status": "failed",
  "failedStepId": "validate_subreddit_rules",
  "failure": {
    "reasonCode": "rules_unavailable",
    "message": "The subreddit rules could not be verified before execution.",
    "retryable": true,
    "failedStepId": "validate_subreddit_rules",
    "remediation": "Refresh subreddit rules in Rankhog, review the planned action, then execute again with a new idempotency key."
  }
}

Credits

Posts, comments, replies, and warm-ups spend credits. Read what a product can spend before queuing work:

curl "$RANKHOG_API_BASE_URL/agent/v1/credits/balance" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "websiteId": "web_..."
  }'
{
  "organizationId": "org_...",
  "websiteId": "web_...",
  "period": {
    "allotment": 100,
    "remaining": 82,
    "available": 82,
    "periodStart": "2026-06-01T00:00:00.000Z",
    "periodEnd": "2026-07-01T00:00:00.000Z",
    "source": "stripe_subscription"
  },
  "bank": { "available": 130, "balance": 130 },
  "available": 212,
  "committed": 4,
  "spendable": 208,
  "costs": { "warmup": 50, "draft": 1, "warmup_draft": 0, "post": 0, "comment": 0, "reply": 0, "upvote": 0, "draft_regeneration": 1, "managed_proxy": 5 },
  "monthlyAllotmentPerProduct": 100,
  "lowBalanceThreshold": 20,
  "products": [{ "websiteId": "web_...", "displayName": "Example SaaS", "available": 212, "committed": 4, "spendable": 208, "period": { "allotment": 100 } }]
}

period is this product's monthly credits, bank is the organization pool shared by every product, and spendable is available minus credits committed to queued actions. Omit websiteId to read the bank alone.

costs is the live price table. A draft (draft) costs credits when it is saved, whether you asked for it or autopilot wrote it. Sending a post, comment, or reply costs 0. A rewrite you ask for is charged draft_regeneration on every second rewrite, so it averages half a credit.

Page through the ledger with /agent/v1/credits/ledger (credits:read). Every grant, purchase, refund, adjustment, and debit is one row with its actorKind and the action, warm-up, purchase, or opportunity it paid for. Pass the previous nextCursor as cursor; it is null on the last page. Member names and user ids are never included.

curl "$RANKHOG_API_BASE_URL/agent/v1/credits/ledger" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "websiteId": "web_...",
    "limit": 25
  }'

Both reads need organization membership only, so they work on lapsed and locked workspaces. execute_reddit_action returns 402 agentic_insufficient_credits with required, available, and spendable when the product cannot spend the action's cost. Buying credit packs, auto top-up, and admin adjustments are billing changes and stay in the Rankhog app.

Idempotency

All writes require a caller idempotencyKey. Rankhog also derives a server-side key from plannedRedditActionId.

  • Duplicate execute calls for the same planned action return the existing execution.
  • Already submitted actions return the existing submitted Reddit action.
  • Ambiguous final-submit states return verification_required; do not blindly retry.

Statuses

get_reddit_action_execution_status returns one of:

queued
running
succeeded
failed
blocked
cancelled
verification_required

verification_required means Reddit may have accepted the final submit, but Rankhog could not prove it. Check Reddit or refresh state before retrying with a new idempotency key.

Safety

Rankhog validates permissions/scopes before queueing execution. The execution layer then checks billing, account grants, action readiness, pacing, URL policy, Desktop readiness, Reddit account match, challenge pages, idempotency, and final verification. Public clients send high-level workflow requests only; raw browser control is not exposed.

Every execution also respects the selected identity's Reddit account protection policy. Weighted hourly and daily budgets and minimum spacing can delay or block an action. REST and organization API keys cannot weaken that human-owned policy.

The retired post-submission endpoint has been removed. Use create_reddit_action, execute_reddit_action, and get_reddit_action_execution_status.

Working the Opportunity Inbox

An agent can now work an opportunity end to end: read it, edit its draft, send it, or cancel it.

curl "$RANKHOG_API_BASE_URL/agent/v1/opportunities/confirm" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "websiteId": "web_...",
    "managedRedditAccountId": "acct_...",
    "opportunityId": "opp_...",
    "when": { "mode": "now" },
    "idempotencyKey": "confirm-opp-001"
  }'

Confirm needs the automation preset (reddit:write:dangerous). /opportunities/cancel cancels pending execution and dismisses the opportunity; /opportunities/draft edits the linked draft with reddit:draft:write and an idempotency key. Poll the returned jobId through /agent/v1/reddit-action-executions/status.

Start a conversation

Start conversation opens a new inbox conversation from a prompt, like typing in New. A Reddit post or comment link becomes a reply card: Rankhog reads the thread and prepares it. Any other prompt becomes a conversation with the agent.

curl "$RANKHOG_API_BASE_URL/agent/v1/conversations" \
  -H "Authorization: Bearer $RANKHOG_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "organizationId": "org_...",
    "websiteId": "web_...",
    "managedRedditAccountId": "acct_...",
    "prompt": "https://www.reddit.com/r/SaaS/comments/abc123/how_do_you_find_first_users/",
    "idempotencyKey": "start-001"
  }'

The response returns opportunityId, conversationId, the kind (reddit_comment, reddit_reply, or user_request) and the outcome. existing means the thread already had a card, and the prompt was added there. Then read the conversation with get_opportunity_conversation.

  • Needs rankhog:read and conversation:write. Limited to 30 starts per actor and product per hour.
  • You may pass your own opportunityId and conversationId (uppercase ULIDs). Sending them again with the same prompt returns the same result; any other use returns agentic_idempotency_conflict.
  • An API key starts the conversation, but the agent does not write a draft for it: drafts cost credits and need a person on the team. Autopilot never sends a started conversation; confirm it yourself.

TypeScript SDK

@rankhog/sdk is a thin typed client generated from this OpenAPI document:

import { createIdempotencyKey, createRankhogClient } from "@rankhog/sdk";

const rankhog = createRankhogClient({ apiKey: process.env.RANKHOG_API_KEY! });

const { items } = await rankhog.post("/agent/v1/opportunities", {
  organizationId: "org_...",
  websiteId: "web_...",
  managedRedditAccountId: "acct_...",
});

await rankhog.post("/agent/v1/opportunities/confirm", {
  organizationId: "org_...",
  websiteId: "web_...",
  managedRedditAccountId: "acct_...",
  opportunityId: items[0]!.id,
  idempotencyKey: createIdempotencyKey("confirm"),
});

Request bodies and responses are fully typed per path, and failures throw RankhogApiError with the error code, request id, and Retry-After seconds.

Errors

Errors use one shape across REST, MCP, and CLI. See the error catalog for every code.

{
  "error": {
    "code": "agentic_missing_scope",
    "message": "Missing required scope: reddit:draft:write.",
    "details": {
      "missingScopes": ["reddit:draft:write"]
    }
  }
}

Every REST response includes x-rankhog-request-id when handled by the agentic API. Rate limited responses (429) include Retry-After seconds.

For AI-assisted integration, every docs page is also raw markdown: append .md to its URL, or fetch /llms.txt for the index and /llms-full.txt for everything in one file.

Next: use the CLI for scripts, or MCP for AI clients with OAuth.

On this page