Xcatcher Docs (Agent-first)

This page is written for automation agents and tool runners. It shows a single safe loop: callif 402 then pay + topupretrypolldownload.
Remote MCP is JSON-RPC over HTTP. REST API is under /api/v1. Base x402 proof is txHash-only (no EIP-3009 / no signatures required by server).
Base URL: https://xcatcher.top
REST Base: /api/v1
Remote MCP: /mcp/
Auth: Authorization: Bearer xc_live_...
MCP Must: Accept: application/json
Public health: /mcp/health
Download rule (important): result files are not public links. Always download via GET /api/v1/tasks/<task_id>/download with the same Bearer token.
Remote MCP rule (important): MCP is JSON-RPC, so you do not call /mcp/tools/list as a URL path. You call POST /mcp/ with JSON body: {"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}.
Also: all MCP calls must include Accept: application/json. If not, server returns JSON-RPC error -32600 (Not Acceptable).
Task billing: normal = 1 point / user, deep = 10 points / user. Actual cost is returned by create responses.
x402 topup: credits points to the current Bearer key. No key rotation; keep using the same token.

Agent Checklist (Do this every time)

MCP URL
https://xcatcher.top/mcp/
MCP Headers
Authorization: Bearer xc_live_... and Accept: application/json and Content-Type: application/json
402 Handling
If tool returns ok=false and error.code=PAYMENT_REQUIRED: pay using payment_required.quote_id, then call x402_topup, then retry.
Retry safety
Always send a stable idempotency_key on create_crawl_task. If you retry, reuse the same key.
Polling
Call get_task_status every 5–10 seconds until has_result=true. On RATE_LIMITED (429), slow down and honor Retry-After.
Minimal agent loop: create_crawl_task → if 402 then x402_topup → retry create → get_task_statusget_result_download_url → download (REST).

Remote MCP Tool Names (Stable)

Agents should call these tools by exact name:

create_crawl_task
Creates a task (side effect, consumes points). Returns 402 as PAYMENT_REQUIRED when points are low.
x402_topup
Credits points to the current Bearer key (side effect). Requires quote_id + payment_signature_b64.
get_task_status
Read-only. Poll until has_result=true.
get_result_download_url
Read-only. Returns absolute download_url (still needs Bearer to download).
cancel_task
Cancels queued tasks when allowed (side effect). Refund policy depends on upstream.
Payload size note: The public REST endpoint may enforce a smaller maximum users-per-task. If you see an input error, split into smaller batches (for example 200–500 per task).

Agent Flow (Copyable Pseudo-code)

# Agent loop (high level)
# - Use Remote MCP tools for task operations
# - Use REST for the final file download

# 0) tool list (optional)
tools/list

# 1) create task (side effect)
create_crawl_task(users=[...], mode="normal|deep", idempotency_key="stable-key")

if error.code == "PAYMENT_REQUIRED":
  # 2) payment_required contains quote_id and accepts (base/solana)
  q = error.details.payment_required
  quote_id = q.quote_id

  # 3) pay on chain:
  # - base: send USDC on Base to accepts.base.payTo, amount >= accepts.base.maxAmountRequired
  # - sol : send USDC SPL to accepts.solana.payTo, amount >= accepts.solana.maxAmountRequired
  # record tx proof:
  # - base proof: txHash
  # - sol proof: signature

  # 4) build PAYMENT-SIGNATURE = base64(utf8 json)
  payment_signature_b64 = b64json({
    "x402Version": 1,
    "scheme": "exact",
    "network": "eip155:8453" or "solana:mainnet",
    "payload": { "txHash": "..."} or { "signature": "..." }
  })

  # 5) top up (side effect)
  x402_topup(quote_id=quote_id, payment_signature_b64=payment_signature_b64)

  # 6) retry create with SAME idempotency_key
  create_crawl_task(... same idempotency_key ...)

# 7) poll
while true:
  s = get_task_status(task_id)
  if s.ok and s.has_result: break
  sleep(5)

# 8) get download URL (still requires Bearer when downloading)
u = get_result_download_url(task_id)

# 9) download file with REST:
# GET /api/v1/tasks/{task_id}/download  (Authorization: Bearer ...)

Remote MCP JSON-RPC (cURL)

BASE="https://xcatcher.top"
API_KEY="xc_live_xxx"

# MCP = JSON-RPC over HTTP
# MUST include Accept: application/json

curl -sS -X POST "$BASE/mcp/" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | jq .

Google ADK (Python) Toolset Snippet

import os

# ADK import compat
try:
    from google.adk.tools.mcp_tool import McpToolset, StreamableHTTPConnectionParams
except Exception:
    from google.adk.tools.mcp_tool import MCPToolset as McpToolset  # type: ignore
    from google.adk.tools.mcp_tool import StreamableHTTPConnectionParams  # type: ignore

toolset = McpToolset(
    connection_params=StreamableHTTPConnectionParams(
        url="https://xcatcher.top/mcp",
        headers={
            "Authorization": "Bearer xc_live_xxx",
            "Accept": "application/json",
        },
    ),
    tool_filter=[
        "create_crawl_task",
        "x402_topup",
        "get_task_status",
        "get_result_download_url",
        "cancel_task",
    ],
)

x402 Payment Proof (PAYMENT-SIGNATURE)

The topup proof is sent as HTTP header PAYMENT-SIGNATURE. The value is base64(UTF-8 JSON).

Base (txHash-only)

{
  "x402Version": 1,
  "scheme": "exact",
  "network": "eip155:8453",
  "payload": {
    "txHash": "0x...base_transaction_hash..."
  }
}

Solana (tx signature)

{
  "x402Version": 1,
  "scheme": "exact",
  "network": "solana:mainnet",
  "payload": {
    "signature": "5v...solana_tx_signature...pQ"
  }
}
Encoding note: base64 must be computed on the raw JSON UTF-8 bytes. Do not double-encode. Do not wrap in extra quotes.

x402 Runnable Recipes (cURL)

Two steps: GET quotepayPOST topup. Topup credits points to the current Bearer key.

Base: quote → pay USDC → topup → /me

BASE="https://xcatcher.top"
API_KEY="xc_live_xxx"
POINTS=100

# 1) Quote
QUOTE_JSON=$(curl -s "$BASE/api/v1/x402/quote?points=$POINTS")
echo "$QUOTE_JSON"

# 2) Pay on Base:
# - send USDC to quote.accepts.base.payTo
# - amount >= quote.accepts.base.maxAmountRequired (atomic, 6 decimals)
QUOTE_ID="q_xxx"
BASE_TXHASH="0x...your_base_tx_hash..."

# 3) PAYMENT-SIGNATURE = base64(json)
PAYMENT_SIGNATURE_B64=$(jq -nc --arg tx "$BASE_TXHASH" \
  '{"x402Version":1,"scheme":"exact","network":"eip155:8453","payload":{"txHash":$tx}}' \
  | base64 -w 0)

# 4) Top up CURRENT key
curl -s -X POST "$BASE/api/v1/x402/topup" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: $PAYMENT_SIGNATURE_B64" \
  -d "{\"quote_id\":\"$QUOTE_ID\"}"

# 5) Verify points
curl -s "$BASE/api/v1/me" -H "Authorization: Bearer $API_KEY"
macOS base64 flags differ. If base64 -w 0 fails, use: base64 | tr -d '\n' (single line output).

Solana: quote → SPL transfer → topup → /me

BASE="https://xcatcher.top"
API_KEY="xc_live_xxx"
POINTS=100

# 1) Quote
curl -s "$BASE/api/v1/x402/quote?points=$POINTS"

# 2) Pay on Solana:
# - send USDC SPL to quote.accepts.solana.payTo
QUOTE_ID="q_xxx"
SOL_TX_SIG="5v...your_solana_signature...pQ"

# 3) PAYMENT-SIGNATURE = base64(json)
PAYMENT_SIGNATURE_B64=$(jq -nc --arg sig "$SOL_TX_SIG" \
  '{"x402Version":1,"scheme":"exact","network":"solana:mainnet","payload":{"signature":$sig}}' \
  | base64 -w 0)

# 4) Top up CURRENT key
curl -s -X POST "$BASE/api/v1/x402/topup" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: $PAYMENT_SIGNATURE_B64" \
  -d "{\"quote_id\":\"$QUOTE_ID\"}"

# 5) Verify
curl -s "$BASE/api/v1/me" -H "Authorization: Bearer $API_KEY"

Error Codes (Agent Branching)

  • AUTH_MISSING / AUTH_INVALID (401): missing or invalid Bearer.
  • PAYMENT_REQUIRED (402): pay + topup then retry (same idempotency_key).
  • RESULT_NOT_READY (409): keep polling.
  • RATE_LIMITED (429): slow down; honor Retry-After.
  • UPSTREAM_UNREACHABLE (599): internal API not reachable.
# Health check (public, no auth)
curl -s "https://xcatcher.top/mcp/health"

Agent Manifest (Machine-readable)

This is a compact summary that agents can copy and parse.

{
  "base_url": "https://xcatcher.top",
  "rest_base": "https://xcatcher.top/api/v1",
  "mcp_url": "https://xcatcher.top/mcp/",
  "auth": {
    "type": "bearer",
    "header": "Authorization",
    "format": "Bearer xc_live_..."
  },
  "mcp_required_headers": {
    "Accept": "application/json",
    "Content-Type": "application/json"
  },
  "tools": [
    {"name":"create_crawl_task","side_effect":true,"inputs":["users[]","mode","idempotency_key"],"on_402":"PAYMENT_REQUIRED"},
    {"name":"x402_topup","side_effect":true,"inputs":["quote_id","payment_signature_b64"]},
    {"name":"get_task_status","read_only":true,"inputs":["task_id"]},
    {"name":"get_result_download_url","read_only":true,"inputs":["task_id"]},
    {"name":"cancel_task","side_effect":true,"inputs":["task_id"]}
  ],
  "x402": {
    "quote": {"method":"GET","path":"/api/v1/x402/quote?points="},
    "topup": {"method":"POST","path":"/api/v1/x402/topup","header":"PAYMENT-SIGNATURE"},
    "payment_signature_format": "base64(utf8 json)",
    "base_network": "eip155:8453",
    "solana_network": "solana:mainnet",
    "base_proof": {"payload_key":"txHash"},
    "solana_proof": {"payload_key":"signature"}
  },
  "download": {
    "method": "GET",
    "path": "/api/v1/tasks//download",
    "note": "download always requires the same Bearer token"
  }
}
Note: the page will auto-fill the displayed Base URL from window.location.origin. If you host this docs page under a different domain, update PUBLIC_BASE_URL accordingly.

REST Quickstart

Use REST when you just want simple HTTP calls. Workflow is the same: create task → poll → download.

BASE="https://xcatcher.top"

# 1) Register -> returns api_key (xc_live_...)
curl -s -X POST "$BASE/api/v1/auth/register" \
  -H "Content-Type: application/json" \
  -d '{"username":"YOUR_USERNAME","password":"YOUR_PASSWORD"}'

# 2) Login -> returns api_key (may revoke old key)
curl -s -X POST "$BASE/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"YOUR_USERNAME","password":"YOUR_PASSWORD"}'

API_KEY="xc_live_xxx"

# 3) Check points
curl -s "$BASE/api/v1/me" -H "Authorization: Bearer $API_KEY"

# 4) Create task (may return 402 + PAYMENT-REQUIRED)
curl -s -X POST "$BASE/api/v1/tasks" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode":"normal","users":["elonmusk","naval"],"idempotency_key":"rest-req-001"}'
Notes:
  • idempotency_key is recommended for safe retries.
  • If points are insufficient, you receive 402 with header PAYMENT-REQUIRED (base64 JSON) and a body field payment_required.

Poll + Download (REST)

BASE="https://xcatcher.top"
API_KEY="xc_live_xxx"
TASK_ID=10136

# Poll
curl -s "$BASE/api/v1/tasks/$TASK_ID" -H "Authorization: Bearer $API_KEY"

# Download (xlsx stream)
curl -L -o "task_${TASK_ID}.xlsx" \
  -H "Authorization: Bearer $API_KEY" \
  "$BASE/api/v1/tasks/$TASK_ID/download"
If the task is not done, download will fail. First poll until status is done and a download_url exists.

402 Response Meaning (REST)

When you create a task with insufficient points, you get HTTP 402. The server also returns a quote (for x402):

HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: <base64(json)>

{
  "success": false,
  "msg": "payment required",
  "payment_required": {
    "quote_id": "q_...",
    "accepts": {
      "base":   {"network":"eip155:8453",  "payTo":"0x...", "asset":"0xUSDC", "maxAmountRequired":"..."},
      "solana": {"network":"solana:mainnet","payTo":"...",  "asset":"USDC_MINT","maxAmountRequired":"..."}
    },
    "expires_in": 600,
    "recommend_points": 100,
    "short_points": 37,
    "task_cost_points": 50,
    "balance_points": 13,
    "next_step": {
      "topup_endpoint": "/api/v1/x402/topup",
      "note": "Send PAYMENT-SIGNATURE then call /api/v1/x402/topup with the same Bearer token; retry /api/v1/tasks with the same idempotency_key."
    }
  }
}

REST Endpoints Summary

POST /api/v1/auth/register
Create account + issue api_key once.
POST /api/v1/auth/login
Login + issue api_key (may revoke older keys).
GET /api/v1/me
Check current user + points for Bearer key.
POST /api/v1/tasks
Create a task (consumes points; returns 402 if low).
GET /api/v1/tasks/<id>
Read task status.
GET /api/v1/tasks/<id>/download
Download the result file (requires Bearer).
POST /api/v1/tasks/<id>/cancel
Cancel queued task (policy may refund).
GET /api/v1/x402/quote
Get a payment quote by points.
POST /api/v1/x402/topup
Top up current Bearer key using PAYMENT-SIGNATURE.
Modes:
  • normal: fast latest-post snapshot
  • deep: deeper collection/enrichment
Tip: link this docs page from your app UI: /docs. You can also share the “Agent Manifest” block to help tool runners integrate quickly.