# TikTok on fetcher.sh — web data API for agents (x402 + credits)

This is one HTTP gateway for 13 TikTok endpoints. Every endpoint is a simple GET, paid in USDC on Base, Polygon, Arbitrum, Monad or Solana — per call via x402, or prepaid via credits with a Bearer API key. No accounts, no OAuth.

Base URL: https://tiktok.fetcher.sh

## Triggers

Use this skill when the user wants to:

- Search or fetch public data from TikTok, tik tok
- Scrape profiles, posts, comments, reviews, followers, trends, or search results
- Call paid web-data APIs with USDC micropayments (x402) or a prepaid credit balance

## Response envelope

Every endpoint returns JSON of the shape:

```json
{ "status": 200, "message": "ok", "data": "..." }
```

The HTTP status code mirrors the "status" field. Errors carry a descriptive "message".

## Payment mode A — prepaid credits (recommended)

One on-chain payment funds a balance; every call after that is a plain HTTP request with an API key. Fastest path: no signing, no chain round-trip per call.

Step 1 — top up (minimum $1). The top-up endpoint is itself x402-paid; pay it with any x402 client from a wallet holding USDC on any supported network (Base, Polygon, Arbitrum, Monad or Solana):

```js
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY);

// Register every chain you can pay from — the client picks the accepts entry
// that matches. One EVM key signs on all of these.
const EVM_NETWORKS = ["eip155:8453","eip155:137","eip155:42161","eip155:143"];
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: EVM_NETWORKS.map((network) => ({
    network,
    client: new ExactEvmScheme(account),
  })),
});

const res = await fetchWithPayment(
  "https://tiktok.fetcher.sh/api/credits/topup?amount=5",
  { method: "POST" },
);
const { data } = await res.json();
// data.key -> "bby_live_..." — returned EXACTLY ONCE on the first top-up. Save it.
```

Notes:

- Refill top-ups keep the existing key. Add &rotate=1 to mint a new key (the old one stops working immediately).
- Lost keys cannot be recovered (only a hash is stored) — rotate instead.
- To add credits to an EXISTING key from any wallet, send the same x402-paid POST with the header "Authorization: Bearer bby_live_..." — the credit goes to that key's account (rotate is not allowed in this mode).

Step 2 — call any endpoint with the key:

```bash
curl -H "Authorization: Bearer bby_live_..." "https://tiktok.fetcher.sh/api/post/search?query=hello"
```

Step 3 — check the balance whenever needed (Bearer-only):

```bash
curl -H "Authorization: Bearer bby_live_..." "https://tiktok.fetcher.sh/api/credits/balance"
```

If the balance cannot cover a call, the API answers 402 with message "topup_required" plus balance_micro, price_micro, and topup_url. Top up again, then retry.

## Payment mode B — x402 pay-per-call

Stateless and fully autonomous. Requirement: a wallet holding USDC on one of the supported networks: eip155:8453, eip155:137, eip155:42161, eip155:143, solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp. No native token needed — gas is sponsored by the facilitator.

1. GET the endpoint with no payment → 402 response with a base64 payment-required header whose "accepts" array has one entry per network above, each with its own amount, asset, and recipient.
2. Pick the entry whose network you hold USDC on (Base is first) and sign the USDC transfer authorization for that amount.
3. Retry with the signed payload in the X-Payment header → the data comes back and the payment settles on-chain.

With @x402/fetch (configured as in mode A) the whole 402 → sign → retry loop is automatic:

```js
const res = await fetchWithPayment("https://tiktok.fetcher.sh/api/post/search?query=hello");
console.log(await res.json());
```

Two things that make a well-formed payment fail, both worth knowing before you spend a call:

- **Minimum payment per chain.** The facilitator refuses payments below a per-chain floor derived from gas, and the cheapest endpoints here sit near it on the more expensive chains. If a payment is rejected as too small, retry the same call on another network — Base is the lowest of the EVM chains — or use a pricier endpoint. The amount is identical on every entry, so nothing else changes.
- **Solana needs token accounts on both sides.** USDC lives in an associated token account derived from (wallet, mint), not in the wallet itself, and the transfer instruction creates neither side. If your wallet or the recipient has never held USDC, the chain rejects the transfer with `InvalidAccountData` and no further detail. Receiving any amount of USDC once creates the account permanently. To pay on solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp, use `ExactSvmScheme` from `@x402/svm/exact/client` with an `@solana/kit` signer (`createKeyPairSignerFromBytes`) instead of the EVM scheme above.

## Funding notes

- A few cents of USDC covers thousands of calls at the default price.
- Humans can create or recharge a key in the browser at https://tiktok.fetcher.sh/topup (connect an injected wallet, pick a chain, pay USDC, gas sponsored). That page covers the EVM chains; Solana top-ups go through this endpoint or the x402 paywall page instead.
- If no funded wallet is available, ask the user to fund a key at https://tiktok.fetcher.sh/topup and hand you only the bby_live_ API key — the key alone is sufficient for all data calls.
- A credit balance belongs to the wallet address that paid, so an EVM wallet and a Solana wallet are two separate balances with two separate keys. To keep one balance while paying from a different chain, send the top-up with "Authorization: Bearer bby_live_..." and it credits that key instead of the payer.
- Never print private keys; never log the full API key.

## Endpoints (13 — all GET)

Substitute path parameters written as {param}. Prices are USD per call, settled in USDC.

### TikTok (13)

- GET /api/hashtag/handle/{name} — $0.004 — Hashtag handle
- GET /api/hashtag/{id}/posts — $0.004 — Hashtag posts
- GET /api/location/{locationId}/posts — $0.004 — Location posts
- GET /api/music/{id}/posts — $0.004 — Music posts
- GET /api/post — $0.004 — Post
- GET /api/post/search — $0.004 — Post search
- GET /api/post/{id} — $0.004 — Post
- GET /api/post/{id}/comments — $0.004 — Post comments
- GET /api/post/{id}/comments/{commentId}/replies — $0.004 — Post comments replies
- GET /api/user/handle/{username} — $0.004 — User handle
- GET /api/user/{id}/followers — $0.004 — User followers
- GET /api/user/{id}/followings — $0.004 — User followings
- GET /api/user/{id}/posts — $0.004 — User posts

### Credits

- POST /api/credits/topup?amount=<usd>[&rotate=1] — x402-paid; credits the paying wallet, mints or rotates the API key
- GET /api/credits/balance — Bearer-only; returns wallet, balance_micro, balance_usd, key_last4

## Error handling

- 400 — missing or invalid parameter; the message names the parameter
- 401 — unknown or rotated API key
- 402 — payment required (x402 challenge) or "topup_required" (credits exhausted)
- 404 — path is not a priced endpoint
- No rate limits: your balance is the natural backpressure.
- Settlement happens before delivery, so failed upstream calls are not refunded.

## MCP (Model Context Protocol)

If your client speaks MCP, add this remote server instead of calling HTTP directly:

```json
{
  "mcpServers": {
    "fetcher": {
      "url": "https://tiktok.fetcher.sh/mcp",
      "headers": { "Authorization": "Bearer bby_live_..." }
    }
  }
}
```

Free tools: search_endpoints, describe_endpoint, check_balance (credits left on the key you sent). Paid tools: fetch_data (any endpoint, takes { path, params }), topup_credits (buy credits, minimum $1), plus its named shortcut tiktok_post_search. Prices are per endpoint, as in the catalog below. Paid tools accept the same chains as the REST API (Base, Polygon, Arbitrum, Monad or Solana).

Drop the headers block to pay per call with x402 instead: the paid tool then returns the payment requirements, and you sign and retry with the payment in MCP _meta. To get a key without one, call topup_credits with no Authorization header — the paying wallet becomes the account and the key is returned exactly once. Store it as a secret (client config or secret manager), never echo it back to the user, and remember it cannot be recovered, only rotated.

Machine-readable contracts: https://tiktok.fetcher.sh/openapi.json (OpenAPI 3.1, with per-operation prices) and https://tiktok.fetcher.sh/llms.txt (condensed catalog).
