402tools402 docs
docs · live

Manage your seller

tools402 has no web dashboard, no login, no admin UI. Every seller operation is an HTTP call signed by your wallet (EIP-712 SellerAction). The four operations below cover the full lifecycle after onboarding.

#Pre-requisite

You have your .tools402-seller.pk file (the same key that registered your slug). All the snippets below assume :

ts
import { existsSync, readFileSync } from "node:fs";
import { privateKeyToAccount } from "viem/accounts";
import { keccak256, toBytes } from "viem";

const pk = readFileSync(".tools402-seller.pk", "utf-8").trim() as `0x${string}`;
const account = privateKeyToAccount(pk);
const WALLET = account.address;
const API = "https://api.tools402.dev";
const DOMAIN = { name: "tools402", version: "1", chainId: 8453 } as const;
const TYPES = { SellerAction: [
  { name: "wallet", type: "address" }, { name: "action", type: "string" },
  { name: "payloadHash", type: "bytes32" }, { name: "timestamp", type: "uint256" },
]} as const;

#Update an endpoint (price, upstream, desc)

There is no UPDATE primitive — instead, delete then re-add. The sequence keeps your slug, only the endpoint id changes.

#Delete an endpoint

ts
const id = 42; // your endpoint id from /v1/_meta
const ts = Math.floor(Date.now() / 1000);
const sig = await account.signTypedData({
  domain: DOMAIN, types: TYPES, primaryType: "SellerAction",
  message: { wallet: WALLET, action: "delete_endpoint", payloadHash: keccak256(toBytes(String(id))), timestamp: BigInt(ts) },
});
await fetch(`${API}/v1/_seller/${WALLET}/endpoints/${id}`, {
  method: "DELETE",
  headers: { "X-Signature": sig, "X-Timestamp": String(ts) },
});
// → 200 OK { ok: true }

The endpoint is soft-deleted (enabled = 0). Buyer calls on this path return 410 Gone immediately. Pending settlements still ship at the next 00:00 UTC cron.

#Resume after suspension

If your endpoint returned 5xx for > 50 % of probes over 10 minutes, the marketplace flipped it to degraded. Sustained outage > 1 hour → suspended (status returned in /v1/_meta).

To resume :

ts
const ts = Math.floor(Date.now() / 1000);
const sig = await account.signTypedData({
  domain: DOMAIN, types: TYPES, primaryType: "SellerAction",
  message: { wallet: WALLET, action: "resume", payloadHash: keccak256(toBytes("")), timestamp: BigInt(ts) },
});
await fetch(`${API}/v1/_seller/${WALLET}/resume`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ wallet: WALLET, signature: sig, timestamp: ts }),
});
// → 200 OK { ok: true, status: "active" }

The marketplace runs another 3-region probe immediately. If it passes, your endpoint flips back to active in /v1/_meta and starts serving again. If it fails, the suspension stays.

#Read your stats

The stats endpoint returns your current activity (calls, revenue, top endpoints, next settlement). It's read-only but still signed (to prevent stalking of arbitrary wallets) :

ts
const ts = Math.floor(Date.now() / 1000);
const sig = await account.signTypedData({
  domain: DOMAIN, types: TYPES, primaryType: "SellerAction",
  message: { wallet: WALLET, action: "stats", payloadHash: keccak256(toBytes("")), timestamp: BigInt(ts) },
});
const r = await fetch(`${API}/v1/_seller/${WALLET}/stats?sig=${sig}&ts=${ts}`);
const stats = await r.json();
// → {
//   "wallet": "0x…", "slug": "your-slug",
//   "revenue_24h_usdc": "0.46", "revenue_total_usdc": "12.83",
//   "calls_24h": 47, "calls_total": 1287,
//   "take_rate": "3%",
//   "top_endpoints": [...],
//   "perf": { p50_ms, p95_ms, p99_ms },
//   "next_settlement": { "in": "8h 12m", "net_usdc": "0.44", "gas_absorbed": true }
// }

#Lose your .tools402-seller.pk file

There is no recovery. Your slug is locked to the wallet that registered it; without the private key, you can't add endpoints, delete endpoints, resume, or move the slug elsewhere. Daily settlement keeps pushing USDC to the wallet's address but you cannot spend it.

Back up .tools402-seller.pk to a password manager the moment you generate it. The onboarding script writes it with mode 0o600; you can also copy the hex content into 1Password, Bitwarden, or any secrets vault.

If your wallet is compromised (private key leaked), you cannot rotate it. You can delete_endpoint everything and start over with a new slug + new wallet. The marketplace does not have any concept of "account ownership" above the wallet.