Xcatcher Docs (x402 + Tasks)

This page matches skill.md exactly: x402 quote (Solana USDC)paybuy_pointsapi_keycreate taskpolldownload.
REST API base is /api/v1. MCP health is optional: /mcp/health.
Base URL: https://xcatcher.top
REST Base: /api/v1
MCP Health: /mcp/health
Auth: Authorization: Bearer xc_live_...
Docs: /docs
Download rule (important): result files are not public links. Always download via GET /api/v1/tasks/<task_id>/download with the same Bearer token.
Pricing (task cost): normal = 1 point / user, deep = 10 points / user. support chain = sol / base.
Do not hardcode any USDC→points rate. Always trust the quote response.
Requirements: curl, jq, base64, plus XCATCHER_API_KEY for authenticated calls.

0) Optional health check

Public endpoint, no auth required.

BASE="https://xcatcher.top"
curl -sS "$BASE/mcp/health"
echo

1) Get x402 quote (points → Solana USDC)

Quotes expire quickly. Pay immediately after receiving the quote.

BASE="https://xcatcher.top"
POINTS=1

curl -sS "$BASE/api/v1/x402/quote?points=$POINTS" | tee quote.json
echo

QUOTE_ID=$(jq -r '.quote_id' quote.json)
USDC_MINT=$(jq -r '.accepts.solana.asset' quote.json)
PAY_TO=$(jq -r '.accepts.solana.payTo' quote.json)
AMOUNT_ATOMIC=$(jq -r '.accepts.solana.maxAmountRequired' quote.json)

echo "QUOTE_ID=$QUOTE_ID"
echo "USDC_MINT=$USDC_MINT"
echo "PAY_TO=$PAY_TO"
echo "AMOUNT_ATOMIC=$AMOUNT_ATOMIC"
echo "USDC_AMOUNT=$(python3 - <<'PY'
import json
q=json.load(open("quote.json"))
amt=int(q["accepts"]["solana"]["maxAmountRequired"])
print(amt/1_000_000)
PY
)"
echo
Do not hardcode any exchange. Always use maxAmountRequired from quote.

2) Pay USDC on Solana mainnet

Send USDC (SPL) to PAY_TO for at least AMOUNT_ATOMIC (USDC has 6 decimals). Record the Solana tx signature.

# Send SPL USDC to PAY_TO for >= AMOUNT_ATOMIC
# Then set:
SOL_SIG="YOUR_SOLANA_TX_SIGNATURE"

3) Build PAYMENT-SIGNATURE header (base64 JSON)

Base64 encode once (no double encoding). Output must be single line.

SOL_SIG="YOUR_SOLANA_TX_SIGNATURE"

PAYMENT_SIGNATURE_B64=$(jq -nc --arg sig "$SOL_SIG" \
  '{"x402Version":1,"scheme":"exact","network":"solana:mainnet","payload":{"signature":$sig}}' \
  | base64 | tr -d '\n')

echo "PAYMENT_SIGNATURE_B64=$PAYMENT_SIGNATURE_B64"
echo

4) Buy points (quote_id + PAYMENT-SIGNATURE → api_key)

This returns an api_key. Export it as XCATCHER_API_KEY.

BASE="https://xcatcher.top"

curl -sS -X POST "$BASE/api/v1/x402/buy_points" \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: $PAYMENT_SIGNATURE_B64" \
  -d "$(jq -nc --arg q "$QUOTE_ID" '{quote_id:$q}')" \
  | tee buy.json
echo

API_KEY=$(jq -r '.api_key' buy.json)
echo "API_KEY=$API_KEY"
export XCATCHER_API_KEY="$API_KEY"
echo "XCATCHER_API_KEY exported."
echo

5) Verify balance (must-do)

Always verify the key works before creating tasks.

BASE="https://xcatcher.top"

curl -sS "$BASE/api/v1/me" \
  -H "Authorization: Bearer $XCATCHER_API_KEY" \
  | jq .
echo

# If you get 402:
# - Most common causes: quote expired or payment proof invalid.
# - Fix: redo steps 1 → 4 with a NEW quote and NEW payment.

6) Create crawl task

Rules: users are X usernames without '@'; always provide idempotency_key.

BASE="https://xcatcher.top"
MODE="normal"               # normal|deep
IDEM="test-idem-001"
USERS_JSON='["user1","user2"]'

echo "ESTIMATED_COST_POINTS=$(python3 - <<'PY'
import json, os
users=json.loads(os.environ.get("USERS_JSON","[]"))
mode=os.environ.get("MODE","normal")
per=1 if mode=="normal" else 10
print(len(users)*per)
PY
)"
echo

curl -sS -X POST "$BASE/api/v1/tasks" \
  -H "Authorization: Bearer $XCATCHER_API_KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -nc --arg mode "$MODE" --arg idem "$IDEM" --argjson users "$USERS_JSON" \
        '{mode:$mode, users:$users, idempotency_key:$idem}')" \
  | tee task.json | jq .
echo

TASK_ID=$(jq -r '.task_id' task.json)
echo "TASK_ID=$TASK_ID"
echo

7) Poll task status until ready

Stop when download_url or result_path is present.

BASE="https://xcatcher.top"

while true; do
  J=$(curl -sS "$BASE/api/v1/tasks/$TASK_ID" -H "Authorization: Bearer $XCATCHER_API_KEY")
  echo "$J" | jq '{task_id,status,status_code,updated_time,error_message,result_path,download_url}'
  HAS=$(echo "$J" | jq -r '(.download_url // .result_path // "") | length')
  if [ "$HAS" -gt 0 ]; then
    echo "DONE"
    break
  fi
  sleep 5
done
echo

8) Download result (XLSX)

Download requires the same Bearer token; results are not public.

BASE="https://xcatcher.top"

curl -sS -L -o "task_${TASK_ID}.xlsx" \
  -H "Authorization: Bearer $XCATCHER_API_KEY" \
  "$BASE/api/v1/tasks/$TASK_ID/download"

echo "Saved: task_${TASK_ID}.xlsx"
echo

Failure handling

  • 401: Bearer token missing/invalid → obtain API key via buy_points or set XCATCHER_API_KEY correctly.
  • 402: quote/proof invalid or expired → redo quote + pay + buy_points (steps 1–4).
  • 429: rate limited → backoff; respect Retry-After if present.
  • Task stuck / upstream issues → report clearly; poll with increasing interval if needed.

Endpoints (stable)

Base URL
https://xcatcher.top
REST Base
/api/v1
Health (optional)
GET /mcp/health
Quote
GET /api/v1/x402/quote?points=<int>
Buy points
POST /api/v1/x402/buy_points (Header: PAYMENT-SIGNATURE)
Me
GET /api/v1/me (Bearer)
Create task
POST /api/v1/tasks (Bearer)
Get task
GET /api/v1/tasks/<task_id> (Bearer)
Download
GET /api/v1/tasks/<task_id>/download (Bearer)
Idempotency: always provide idempotency_key when creating tasks. If retrying the same logical request, reuse the same key.

PAYMENT-SIGNATURE format (Solana)

Header value is base64(UTF-8 JSON).

{
  "x402Version": 1,
  "scheme": "exact",
  "network": "solana:mainnet",
  "payload": {
    "signature": "YOUR_SOLANA_TX_SIGNATURE"
  }
}
Encoding rules: - Base64 encode once (no double encoding).
- Do not wrap the header value in extra quotes.
- Keep it on one line (use tr -d '\n').

Quote response fields you should read

  • quote_id: used in buy_points request body.
  • accepts.solana.payTo: recipient SPL address.
  • accepts.solana.asset: USDC mint.
  • accepts.solana.maxAmountRequired: USDC atomic units (6 decimals).
  • expires_in: quote TTL (pay quickly).

Task cost estimation

For planning only:

mode=normal
1 point / user
mode=deep
10 points / user
estimated_cost
users_count × (mode == normal ? 1 : 10)
Important: This is only an estimate for task points. Payment quote is authoritative for USDC amount.
Tip: you can link this docs page from your app UI as /docs.