Bulk-create Hark accounts and expose the whole pool as one OpenAI-compatible provider for 9Router.
Headless signup · cookie-session capture · round-robin pool · zero dependencies
hark-pool is a small, auditable toolkit that:
- Creates Hark accounts headlessly — no browser. It spins up a mail.tm inbox, requests Hark's magic link, verifies it, sets a password and clears the age gate.
- Captures each session — Hark uses Better-Auth cookies (there is no bearer token), so
the toolkit stores
__Secure-hark.session_tokenand the session id per account. - Pools them behind one OpenAI endpoint —
adapter.jsturns the cookie-based, poll-based Hark chat into a standardPOST /v1/chat/completions. - Wires the pool into 9Router — one OpenAI-compatible provider-node ("Hark") that any CLI/IDE pointed at 9Router can use.
OpenAI client ──▶ 9Router :20128/v1 ──▶ provider-node "Hark"
──▶ adapter :8790/v1 ──▶ round-robin N Hark accounts
──▶ hark.com /api/messages/{send,history} (cookie auth)
See STRUCTURE.md for the full topology, file map and data-flow diagrams.
Hark's chat API is not OpenAI-shaped:
| Step | Hark | OpenAI |
|---|---|---|
| Send | POST /api/messages/send?cid=… → {success:true} immediately |
single call returns the answer |
| Receive | poll GET /api/messages/history?conversationId=… |
returns inline (or SSE) |
| Auth | httpOnly cookie | Authorization: Bearer |
adapter.js hides that difference so 9Router and every downstream tool only ever see a normal
OpenAI provider. Accounts are used round-robin; a dead session is cooled down and the request
retries on another account.
- Node.js 18+ (uses the built-in
fetch). Nonpm install, no dependencies, no build step. - Network access to
hark.com,auth.hark.com,api.mail.tm, and your local 9Router. - A running 9Router only for the connector step.
# 0) (optional) verify a pool you already have
node selftest.js
# 1) create accounts -> accounts.json
node bulk.js --count 5 --concurrency 2
# 2) run the OpenAI-compatible pool
PORT=8790 ACCOUNTS=accounts.json node adapter.js
# 3) install + run 9Router (dashboard: http://localhost:20128)
npm install -g 9router && 9router
# remote/first run: set INITIAL_PASSWORD before launching (default password: 123456)
# 4) connect Hark into 9Router
node connect-9router.js --base http://localhost:20128 --password 123456 \
--adapter http://localhost:8790Point any OpenAI client at 9Router:
Base URL : http://localhost:20128/v1
API Key : <copy from the 9Router dashboard>
Model : hark/account-1 # any hark/* model; the adapter round-robins the pool
| Flag | Default | Meaning |
|---|---|---|
--count N |
1 |
accounts to create |
--concurrency N |
2 |
parallel workers |
--out file |
accounts.json |
output file (appended) |
--domain d |
first active mail.tm domain | mail.tm domain |
--birthday YYYY-MM-DD |
1995-06-15 |
birthday (must be 18+) |
--password "…" |
random | fixed Hark password (else random per account) |
--connect <url> |
— | run the 9Router connector afterwards |
Each run appends to accounts.json, so you can grow the pool over time. Failures retry 3×.
| Var | Default | Meaning |
|---|---|---|
PORT |
8790 |
listen port |
ACCOUNTS |
accounts.json |
pool file |
COOLDOWN_MS |
60000 |
how long a failed account is benched |
| Flag | Default | Meaning |
|---|---|---|
--base |
http://localhost:20128 |
9Router URL |
--password |
123456 |
9Router dashboard password |
--adapter |
http://localhost:8790 |
adapter base URL |
--accounts |
accounts.json |
pool file (for the connection label) |
{
"email": "hark…@maxxspace.com",
"password": "Hark-…",
"userId": "f1Yz…",
"sessionToken": "Tlsy…",
"sessionId": "QFpj…",
"expiresAt": "2026-11-06T11:13:11.077Z",
"cookies": {
"__Secure-hark.session_token": "…",
"__Secure-hark.region": "us",
"__Secure-hark.access": "app"
},
"cookieHeader": "__Secure-hark.session_token=…; __Secure-hark.region=us; __Secure-hark.access=app",
"mailbox": { "address": "…", "password": "…", "token": "…" },
"birthday": "1995-06-15",
"region": "us",
"createdAt": "2026-10-07T11:13:11.976Z"
}
accounts.jsonholds live credentials and is git-ignored. Onlyaccounts.sample.json(redacted) is committed.
| # | Call | Notes |
|---|---|---|
| 1 | POST https://api.mail.tm/accounts |
create inbox, get address + JWT |
| 2 | POST https://auth.hark.com/api/auth/sign-in/magic-link {email, callbackURL} |
→ {"status":true} |
| 3 | poll GET https://api.mail.tm/messages |
read "Your Hark sign-in link" |
| 4 | GET …/magic-link/verify?token=… |
sets the session cookies |
| 5 | POST …/set-password {newPassword} |
requires Origin: https://hark.com |
| 6 | PATCH https://hark.com/api/profile {updates:{birthday}} |
flips hasAppAccess to true |
| 7 | GET …/get-session |
confirms emailVerified:true, returns session.token |
Chat: POST /api/messages/send?cid=…, then poll GET /api/messages/history?conversationId=…
for the assistant's send_bubble message.
- Hark exposes Claude Opus / Sonnet / Haiku and chooses the model server-side; there is no chat model picker, so the adapter forwards your prompt as-is.
- mail.tm rate limits: ~1 account creation per 60s per IP, and reads are throttled. The bulk creator waits 65s between creations and polls gently.
- This uses Hark's private web API; it can change without notice. Treat endpoint shapes as unverified against future builds.
- Pooling many accounts draws on Hark's own usage meters and may trip abuse controls. Use responsibly.
Issues and pull requests are welcome. Keep the zero-dependency rule: if it isn't already in Node 18, don't add it.
This project is unaffiliated with Hark or 9Router. It automates account creation against a third-party service; you are responsible for complying with that service's terms of use and any applicable law. Provided for educational and interoperability purposes.
MIT © 2026 0xgetz