# TPN Documentation ## Billing There are two billing methods. The route determines which one applies — credits routes require an API key, x402 routes do not. ### Credits (API Key) Credits are tied to your API key. Your first key receives 100 credits for free. Additional credits are purchased via Stripe. #### Packages | Package | Credits | Price | | ------- | ------- | ------- | | Starter | 1,000 | $9.99 | | Pro | 5,000 | $49.99 | | Premium | 20,000 | $199.99 | #### Cost per lease Credits are calculated from the requested duration: ``` credits = ceil(4.1 * minutes^0.375) ``` | Minutes | Credits | | ------- | ------- | | 1 | 5 | | 5 | 8 | | 10 | 10 | | 30 | 15 | | 60 | 20 | | 120 | 25 | | 720 | 49 | | 1440 | 63 | Use `POST /api/v1/vpn/cost` to calculate credits for any duration without generating a lease. #### Check balance ```bash curl https://api.taoprivatenetwork.com/api/v1/user/balance \ -H "X-API-Key: tpn-your-api-key" ``` Returns `credits` (remaining) and `totalUsed`. ### x402 (Pay-per-request) x402 routes use on-chain payments. No API key is required. Currently settled in **USDC on Base**. The price per request is derived from the same credit formula above, converted to USD at a server-configured rate. The exact amount and payment destination are returned in the `PAYMENT-REQUIRED` header on the initial 402 response. #### Flow 1. Send the request without any payment headers. 2. Receive a **402** response with a `PAYMENT-REQUIRED` header and a body containing `creditsRequired`, `priceUsd`, and `minutes`. 3. Sign and attach the payment, then retry the same request with the `PAYMENT-SIGNATURE` header. #### Example — unpaid request ```bash curl -i \ -H "Content-Type: application/json" \ -d '{"minutes":60,"format":"json","connection_type":"any"}' \ https://api.taoprivatenetwork.com/api/v1/x402/vpn/generate ``` #### Example — full client flow (TypeScript) ```ts import { x402Client } from "@x402/core/client"; import { x402HTTPClient } from "@x402/core/http"; import { ExactEvmClient } from "@x402/evm"; import { toClientEvmSigner } from "@x402/evm"; const signer = toClientEvmSigner(/* your Base wallet signer */); const http = new x402HTTPClient( new x402Client().register("eip155:*", new ExactEvmClient(signer)), ); const url = "https://api.taoprivatenetwork.com/api/v1/x402/vpn/generate"; const body = JSON.stringify({ minutes: 60, format: "json", connection_type: "any", }); const unpaid = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body, }); if (unpaid.status === 402) { const paymentRequired = http.getPaymentRequiredResponse( (name) => unpaid.headers.get(name), await unpaid.json(), ); const paymentPayload = await http.createPaymentPayload(paymentRequired); const paid = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", ...http.encodePaymentSignatureHeader(paymentPayload), }, body, }); const response = await paid.json(); console.log("Paid response:", response); } ``` ## Endpoints Base URL: `https://api.taoprivatenetwork.com` Interactive Swagger UI: [`https://api.taoprivatenetwork.com/api-docs/`](https://api.taoprivatenetwork.com/api-docs/) All routes are under `/api/v1`. Auth column: **Key** = `X-API-Key` header required, **x402** = on-chain payment required, **—** = none. ### Health #### `GET /api/v1/health` **Auth:** — **Response 200** ```json { "message": "OK!" } ``` ### Generate (Credits) These routes deduct credits from the API key balance. #### `POST /api/v1/vpn/generate` **Auth:** Key **Body** | Field | Type | Default | Description | | ----------------- | -------------------------------------------- | -------- | -------------------------------------------------------------------------- | | `minutes` | integer | required | Lease duration. 1–1440. | | `geo` | string | — | Country code to target (e.g. `"US"`). | | `format` | `"text"` \| `"json"` | `"text"` | Config output format. | | `connection_type` | `"any"` \| `"datacenter"` \| `"residential"` | `"any"` | Connection type filter. | | `whitelist` | `string[]` | — | Optional. Request workers that match these specific IPv4 addresses. | | `blacklist` | `string[]` | — | Optional. Request workers that do NOT match these specific IPv4 addresses. | **Response 200** ```json { "success": true, "vpnConfig": "", "geo": "US", "minutes": 30, "expiresAt": "2026-02-04T12:30:00.000Z", "creditsUsed": 15, "usedFallback": false, "type": "wireguard", "connection_type": "any", "whitelist": ["1.1.1.1"], "blacklist": ["8.8.8.8", "1.1.1.1"] } ``` **Errors:** 400 (invalid params), 401 (missing/invalid key), 402 (insufficient credits), 500, 503 (service unavailable — credits refunded) #### `POST /api/v1/proxy/generate` **Auth:** Key Same body and error codes as `/vpn/generate`. Response `type` is `"socks5"` and `vpnConfig` contains the SOCKS5 connection details. ### Generate (x402) Same body schema as the credits routes. No API key needed — payment is handled via x402 headers. An unpaid request returns **402** with pricing info; see [Billing](/billing) for the full flow. #### `POST /api/v1/x402/vpn/generate` **Auth:** x402 **Response 402 (unpaid)** ```json { "error": "Payment required", "creditsRequired": 20, "priceUsd": "$0.80", "minutes": 60 } ``` **Response 200 (paid)** — same shape as `POST /vpn/generate`. **Errors:** 400, 402 (payment required), 500, 503 #### `POST /api/v1/x402/proxy/generate` **Auth:** x402 Same as `/x402/vpn/generate` but returns a SOCKS5 lease. ### Cost #### `POST /api/v1/vpn/cost` **Auth:** — Calculate the credit cost for a given duration without generating a lease. **Body** ```json { "minutes": 60 } ``` **Response 200** ```json { "minutes": 60, "credits": 20, "formula": "credits = 4.1 * minutes^0.375 (rounded up)" } ``` **Errors:** 400 (invalid minutes), 500 ### Countries #### `GET /api/v1/vpn/countries` **Auth:** — Returns the list of available countries for lease generation. **Query params** | Param | Values | Default | | ----------------- | -------------------------------------- | ------- | | `format` | `json` \| `text` | `json` | | `type` | `code` \| `name` | `code` | | `connection_type` | `any` \| `datacenter` \| `residential` | `any` | **Response 200 (format=json, type=code)** ```json ["US", "GB", "FR", "DE"] ``` **Response 200 (format=text)** ``` US GB FR DE ``` **Errors:** 400 (invalid params), 500 ### Stats #### `GET /api/v1/vpn/stats` **Auth:** — Network statistics from the VPN validators. **Response 200** ```json { "mode": "mainnet", "countryCount": { "US": 50, "GB": 30 }, "countryCodeToIps": { "US": ["1.2.3.4"], "GB": ["5.6.7.8"] }, "minerUidToIp": { "miner1": "1.2.3.4" } } ``` **Errors:** 500 ### Balance #### `GET /api/v1/user/balance` **Auth:** Key Returns the credit balance for the authenticated API key. **Response 200** ```json { "apiKeyId": "abc123", "credits": 950, "totalUsed": 50 } ``` **Errors:** 401 (missing/invalid key), 500 ## Lease A lease is a time-limited VPN or proxy configuration. The `vpnConfig` field in the generate response contains the connection details. The `format` body parameter controls the shape. ### WireGuard #### Text format (default) A standard WireGuard INI config: ```ini [Interface] Address = 10.0.0.2/32 PrivateKey = ListenPort = 51820 DNS = 8.8.8.8 [Peer] PublicKey = PresharedKey = AllowedIPs = 0.0.0.0/0 Endpoint = :51820 ``` #### JSON format Set `"format": "json"` to receive a structured object instead: ```json { "interface": { "Address": "10.0.0.2/32", "PrivateKey": "", "ListenPort": "51820", "DNS": "8.8.8.8" }, "peer": { "PublicKey": "", "PresharedKey": "", "AllowedIPs": "0.0.0.0/0", "Endpoint": ":51820" } } ``` ### SOCKS5 Proxy #### Text format (default) A SOCKS5 URI: ``` socks5://:@: ``` #### JSON format Set `"format": "json"` to receive a structured object instead: ```json { "username": "", "password": "", "ip_address": "", "port": 1080 } ``` ### Expiry Leases expire after the requested number of minutes. The `expiresAt` field in the response is an ISO 8601 timestamp calculated as request time + duration. ``` expiresAt = now + minutes ``` ### Worker Selection Filters You can influence which worker is selected for a lease by providing optional `whitelist` and `blacklist` arrays of IPv4 addresses. * **Whitelist**: Only select workers whose public exit IP matches an address in this list. * **Blacklist**: Do not select any workers whose public exit IP matches an address in this list. For more details on implementation, see the [Endpoints](/endpoints#worker-selection-filters) documentation. ## Getting Started **Base URL** ``` https://api.taoprivatenetwork.com ``` All endpoints are prefixed with `/api/v1`. ### Two ways to pay | Method | Auth | How it works | | --------------------- | ------------------ | --------------------------------------------- | | **API Key (credits)** | `X-API-Key` header | Deducts credits from your balance per request | | **x402** | Payment headers | Pay per request on-chain, no API key needed | See [Billing](/billing) for packages, pricing, and the x402 flow. ### API Key API keys are created through the client app. Each key has the format `tpn-`. Your first key is credited with 100 credits automatically. Pass the key in every request via the `X-API-Key` header. ### First request Generate a 30-minute WireGuard VPN lease: ```bash curl -X POST https://api.taoprivatenetwork.com/api/v1/vpn/generate \ -H "Content-Type: application/json" \ -H "X-API-Key: tpn-your-api-key" \ -d '{"minutes": 30}' ``` A successful response returns the WireGuard config, an expiry timestamp, and credits used. See [Lease](/lease) for the response shape and [Endpoints](/endpoints) for the full reference. ## Become a mining pool Becoming a mining pool on the TPN subnet involves running and managing a server that runs Bittensor subnet code in combination with docker containers. You can view detailed instructions on how to set up a miner on the [TPN subnet Github page](https://github.com/taofu-labs/tpn-subnet). ## Become a worker Get your TPN worker up and running quickly using the official scripts. This guide includes all necessary steps in one place. ### 1. Prepare Your Addresses Before starting, have the following ready: * **EVM Address** — for payouts (if applicable) * **Bittensor (TAO) Address** — for network rewards ### 2. Select a Mining Pool Pick a pool with a good reward payout: * Visit [pool.taoprivatenetwork.com](https://pool.taoprivatenetwork.com) * Copy the pool url from the mining pool you want to use ### 3. Install & Configure the Worker Run the one-line installer: ```bash curl -s [https://raw.githubusercontent.com/taofu-labs/tpn-subnet/refs/heads/main/scripts/install_worker.sh](https://raw.githubusercontent.com/taofu-labs/tpn-subnet/refs/heads/main/scripts/install_worker.sh) | bash ``` * The script will prompt you for: * **EVM address** * **Bittensor (TAO) address** * **Mining pool url** * It will install dependencies (Docker, WireGuard, etc.) * Attempts to start the worker automatically ### 4. Update & Restart the Worker To make sure your worker is running the latest version: ```bash bash ~/tpn-subnet/scripts/update_node.sh ``` * Pulls the latest docker image * Restarts the worker ### Notes & Tips * Run on a **Linux machine** with `sudo` privileges * Keep your addresses and pool info handy for prompts * You can rerun `update_node.sh` anytime to refresh your worker