# Token Harbor autoreg ## Platform - **URL**: https://tokenharbor.ai - **Auth**: Email + password → verify email → API key - **Bonus**: $5 gift after email verification (claim flow: gift → verify email → gift → claim) - **Models**: 21 total (3 free, 18 paid) — see below ## Registration flow 1. **Signup**: POST/GET `https://tokenharbor.ai/login?mode=signup` — email + password + confirm 2. **Verify email**: IMAP check for email from `hello@tokenharbor.ai`, follow `https://tokenharbor.ai/verify-email?token=...` 3. **Claim gift**: Navigate to dashboard, click "1 gift ready to claim" → modal → after verify, click "Claim" → $5 appears as "CURRENT BALANCE $5.00" 4. **API key**: `https://tokenharbor.ai/dashboard/api-keys` → create → copy key ## Key verification - Without email verification: `{"error": {"message": "Verify your email to make API calls...", "type": "email_not_verified"}}` - Verified key: `/v1/models` returns model list ## Models (21 total, 2026-08-08) ### Free (3) - `kimi-k3:free` - `mimo-v2.5:free` - `deepseek-v4-flash:free` ### Paid (18) - `claude-sonnet-5`, `claude-opus-5`, `claude-fable-5` - `gpt-5.6-sol`, `gpt-5.6-luna`, `gpt-5.6-terra` - `gemini-3.1-pro-preview`, `gemini-3.6-flash` - `grok-4.5` - `deepseek-v4-pro`, `deepseek-v4-flash` - `qwen3.8-max` - `glm-5.2` - `kimi-k3` - `minimax-m3` - `mimo-v2.5`, `mimo-v2.5-pro` - `th-orchestra` ## Email pool - t-online.de IMAP: `secureimap.t-online.de:993` - File: `C:/Users/User/Downloads/Telegram Desktop/working_mails.txt` (17893 email:password) - Gmail for verification proxy: `[REDACTED-NAME]@gmail.com` ## Gateway - `th_gateway.py` at `C:\Users\User\Desktop\авторег проект\` - Port 8003, Bearer auth, key persistence in `th_gateway_state.json` - Endpoints: `/status`, `/key`, `/keys`, `/models`, `/chat`, `/register?count=N` ## CDP websocket automation (2026-08-08 — tested working) The `tokenharbor_autoreg.py` script has a `global CDP_PORT` bug (Python 3.12+ rejects `global` after module-level usage). Fix: `globals()["CDP_PORT"] = args.port`. **Manual CDP flow** (when script fails — reliable): ```python import json, urllib.request, time, websocket, re # Connect to existing tokenharbor tab or create new tabs = json.loads(urllib.request.urlopen("http://127.0.0.1:9222/json").read()) th_tab = next(t for t in tabs if "tokenharbor" in t.get("url", "")) ws = websocket.create_connection(th_tab["webSocketDebuggerUrl"], timeout=10) msg_id = 0 def js(code, timeout=10): global msg_id msg_id += 1 mid = msg_id ws.send(json.dumps({"id": mid, "method": "Runtime.evaluate", "params": {"expression": code, "returnByValue": True, "awaitPromise": True}})) start = time.time() while time.time() - start < timeout: ws.settimeout(1) try: data = json.loads(ws.recv()) if data.get("id") == mid: r = data.get("result", {}).get("result", {}) return r.get("value"), data.get("subtype") except: pass return None, "timeout" # Navigate: ws.send(json.dumps({"id": mid, "method": "Page.navigate", "params": {"url": url}})) ``` **Key creation via CDP** (no email verification needed for NEW keys): 1. Navigate to `/dashboard/api-keys` 2. Click `+ New key` button 3. Fill label input: `nativeInputValueSetter.call(inp, 'label')` + `dispatchEvent(new Event('input'))` 4. Click `Create key` — React enables the button only when input value changes via native setter 5. Key appears in plaintext: `thk_live_...` — grab it immediately (won't show again) **Key reveal via CDP** (existing key — requires email verification): 1. Click `Show plaintext key` → dialog opens → `Send verification code` 2. **Pitfall**: May fail with `Error sending magic link email` — tokenharbor backend issue 3. Workaround: create a NEW key instead of revealing existing one **Gift claim via CDP**: 1. Navigate to `/dashboard`, click button with text `gift` + `claim` 2. Dialog appears with `Claim` button — click it 3. Balance updates to `$5.00` — verify on `/dashboard/billing` (`CURRENT BALANCE $5.00`) ## Pitfalls - **Cloudflare Turnstile (2026-08-08 — NEW)**: `GET /api/auth/signup-precheck` returns `{\"needCaptcha\":true}`. The Turnstile widget runs in the browser and blocks CDP automation — CDP-based checkbox goes to `failure_retry`. Manual click or 2captcha/Anti-Captcha solver required. This is why the signup form sometimes fails to render properly — the React app waits for Turnstile to resolve before showing the email/password fields. - **CDP signup partially working (2026-08-08)**: 1 of 2 attempts succeeded via CDP (`autoreg_mass.py`). The form rendered in one CDP tab but not another. Turnstile timing is the likely cause — sometimes the challenge resolves quickly, sometimes it stalls. - **Guerrilla Mail works (2026-08-08)**: `api.guerrillamail.com` provides disposable emails. Domain `@guerrillamailblock.com` — on disposable blocklists but TokenHarbor currently accepts it. Use `f=get_email_address` to create, `f=get_email_list` to poll inbox, `f=fetch_email` to read body. No API key needed. Account `yrkypmpq@guerrillamailblock.com` registered successfully and redirected to dashboard. - **Rate-limit error masking (2026-08-10)**: The error `"We couldn't create your account right now"` on the signup form is a GENERIC Supabase error that MASKS the real rate limit. The true error `"Too many sign-ups from this network. Please try again in an hour."` only appears on the LOGIN form AFTER the signup fails. To diagnose: after a failed signup, switch to the login tab and check the error message there. The signup form shows the generic error; the login form shows the real rate-limit message. This causes wasted attempts — you think it's a backend issue when it's actually IP rate-limiting. - **3G IP bypasses rate limit (2026-08-10)**: The Vodafone 178.x.x.x 4G subnet gets rate-limited after ~4-5 signup attempts. Switching to 3G (WCDMA) via ZTE router gives a DIFFERENT IP that works. Confirmed: 4G IP `[REDACTED-IP]` → rate-limited, 3G IP `[REDACTED-IP]` → signup succeeded. The 3G pool appears to have a separate rate-limit counter from 4G. - **API key auto-created on signup (2026-08-10)**: `GET /api/keys` returns `mintedPlaintext` with the full key immediately after signup — no need to manually click "Create key" in the dashboard. The "Universal Key" is auto-generated. Use `page.evaluate()` to call `fetch('/api/keys')` and extract `mintedPlaintext`. - **$5 welcome credit NOT auto-applied (2026-08-10)**: After successful signup, balance shows `$0.00`. The $5 requires email verification + gift claim flow. Dashboard shows `"1 gift ready to claim"` only after email is verified. Without verification, the account has $0 balance but the API key still works for free models. - **t-online.de IMAP delivery issues**: TokenHarbor verification emails to t-online.de addresses are unreliable — some arrive, some don't. IMAP polling for `[REDACTED-EMAIL]`, `[REDACTED-EMAIL]`, `[REDACTED-EMAIL]` all timed out (90s). TokenHarbor may throttle or block based on domain reputation. - **Next.js client-rendered form (2026-08-08)**: The signup page at `login?mode=signup` is a Next.js app with client-side rendering. Form fields (email, password) are NOT in the initial HTML — they're rendered by React after JS loads. The DOM snapshot shows only hidden inputs (`$ACTION_REF_1`, `$ACTION_KEY`, `device_fingerprint`, `timezone`). Wait for the React app to hydrate before filling fields. The form submission is a Next.js server action, not a standard REST API. - **Gmail +aliases blocked**: tokenharbor detects `+` and returns "This email is already on board" - **CDP Chrome required**: Chrome must run with `--remote-debugging-port=9222 --remote-allow-origins=*` - **Gift flow**: Two-step — first claim sends verification email, second claim after verify actually credits $5 - **Registration failures**: First few emails from t-online.de pool may fail (password changed, account disabled) - **React input fill**: `input.value = 'text'` alone doesn't enable React submit buttons. Use `Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set.call(el, val)` + `dispatchEvent(new Event('input', {bubbles:true}))` - **`global CDP_PORT` bug**: Python 3.12+ — `global` before module-level assignment is `SyntaxError`. Use `globals()["CDP_PORT"] = value` - **Key reveal vs new key**: `Show plaintext key` requires email verification code (may fail). Creating a NEW key shows the key immediately without verification.