#!/usr/bin/env python3 """ Hyperion — the App Store for AI agents. Single-file Flask service. Dark premium UI. Simple auth (username + password, no KYC). Bitcoin-settled subscription via BTCPay. API keys issued programmatically. Run: python3 app.py -> binds 0.0.0.0:5000 (BTCPay webhook posts to /webhook/btcpay) """ import os import json import time import secrets import sqlite3 import hashlib import hmac import threading import requests import urllib3 from flask import ( Flask, request, jsonify, redirect, session, render_template_string, abort, g, ) from werkzeug.security import generate_password_hash, check_password_hash try: urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) except Exception: pass app = Flask(__name__) app.secret_key = os.environ.get("HYPERION_SECRET", "hyperion-secret-" + str(int(time.time()))) # --------------------------------------------------------------------------- # Config (from Phase 2 state). Overridable via env. # --------------------------------------------------------------------------- BTCPAY_URL = os.environ["HYPERION_BTCPAY_URL"] BTCPAY_STORE = os.environ["HYPERION_BTCPAY_STORE"] BTCPAY_KEY = os.environ["HYPERION_BTCPAY_KEY"] BTCPAY_WALLET= os.environ["HYPERION_BTCPAY_WALLET"] # Stripe (card payments) — parallel rail to BTCPay. Empty strings = disabled. STRIPE_SK = os.environ.get("HYPERION_STRIPE_SK", "") STRIPE_PK = os.environ.get("HYPERION_STRIPE_PK", "") STRIPE_WHSEC = os.environ.get("HYPERION_STRIPE_WHSEC", "") STRIPE_API = "https://api.stripe.com/v1" STRIPE_REDIRECT = "https://hyperion.thetempleofdoom.com" PRICE_USD = 19.0 # Pro $19/mo (from state pricing) PLAN_MONTHS = [1, 6, 12] # one-price default; monthly GITHUB_URL = "https://gitea.thetempleofdoom.com/drjones/hyperion-app" BMAC_URL = "https://buymeacoffee.com/r26xrthzttg" NEXUS_URL = os.environ.get("HYPERION_NEXUS_URL", "http://10.30.20.46:3000") # Omninexus MCP hub (execution engine) DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "hyperion.db") # --------------------------------------------------------------------------- # SQLite # --------------------------------------------------------------------------- def get_db(): if "db" not in g: g.db = sqlite3.connect(DB_PATH) g.db.row_factory = sqlite3.Row return g.db @app.teardown_appcontext def close_db(exc): db = g.pop("db", None) if db is not None: db.close() def init_db(): db = sqlite3.connect(DB_PATH) db.executescript( """ CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL, email TEXT, api_key TEXT, plan TEXT DEFAULT 'free', pro_expires TEXT, call_count INTEGER DEFAULT 0, created_at TEXT ); CREATE TABLE IF NOT EXISTS invoices ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, btcpay_invoice_id TEXT UNIQUE, checkout_link TEXT, amount REAL, currency TEXT, status TEXT, created_at TEXT ); """ ) db.commit() # migrate: Stripe columns (idempotent) cols = [r[1] for r in db.execute("PRAGMA table_info(invoices)").fetchall()] if "provider" not in cols: db.execute("ALTER TABLE invoices ADD COLUMN provider TEXT DEFAULT 'btcpay'") if "stripe_session_id" not in cols: db.execute("ALTER TABLE invoices ADD COLUMN stripe_session_id TEXT") db.commit() db.close() # --------------------------------------------------------------------------- # BTCPay helpers # --------------------------------------------------------------------------- def btcpay_headers(): return {"Authorization": "Bearer " + BTCPAY_KEY} def create_invoice(description, metadata): """Create a BTCPay invoice for PRICE_USD. Returns dict with id + checkoutLink.""" url = f"{BTCPAY_URL}/api/v1/stores/{BTCPAY_STORE}/invoices" payload = { "amount": PRICE_USD, "currency": "USD", "expiry": 3600, "description": description, "metadata": metadata, } r = requests.post(url, headers=btcpay_headers(), json=payload, verify=False, timeout=20) r.raise_for_status() return r.json() def fetch_invoice(inv_id): url = f"{BTCPAY_URL}/api/v1/stores/{BTCPAY_STORE}/invoices/{inv_id}" r = requests.get(url, headers=btcpay_headers(), verify=False, timeout=20) r.raise_for_status() return r.json() # --------------------------------------------------------------------------- # Stripe helpers (card payments) — reusable, no stripe SDK dependency (requests only) # --------------------------------------------------------------------------- def stripe_headers(): return {"Authorization": "Bearer " + STRIPE_SK} def create_stripe_checkout(user_id, email): """Create a Stripe Checkout Session for Pro ($19/mo). Returns dict with id + url.""" payload = { "mode": "payment", "success_url": STRIPE_REDIRECT + "/dashboard?paid=stripe&session_id={CHECKOUT_SESSION_ID}", "cancel_url": STRIPE_REDIRECT + "/dashboard?canceled=1", "client_reference_id": str(user_id), "metadata[user_id]": str(user_id), "metadata[plan]": "pro", "line_items[0][price_data][currency]": "usd", "line_items[0][price_data][product_data][name]": "Hyperion Pro (1 month)", "line_items[0][price_data][unit_amount]": str(int(PRICE_USD * 100)), "line_items[0][quantity]": "1", "payment_method_types[0]": "card", } if email: payload["customer_email"] = email r = requests.post(f"{STRIPE_API}/checkout/sessions", headers=stripe_headers(), data=payload, timeout=20) r.raise_for_status() return r.json() def verify_stripe_webhook(payload_bytes, sig_header): """Verify Stripe-Signature (v1 scheme = HMAC-SHA256(whsec, 't.payload')). Returns event dict or None.""" if not STRIPE_WHSEC or not sig_header: return None parts = {} for kv in sig_header.split(","): k, _, v = kv.partition("=") parts[k.strip()] = v.strip() ts = parts.get("t", "") sig = parts.get("v1", "") if not ts or not sig: return None signed = f"{ts}.{payload_bytes.decode('utf-8', 'replace')}".encode() expected = hmac.new(STRIPE_WHSEC.encode(), signed, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, sig): return None return json.loads(payload_bytes.decode("utf-8", "replace")) PAID_STATES = {"Paid", "Settled", "Confirmed", "Expired-and-paid"} def now_iso(): return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()) # --------------------------------------------------------------------------- # Auth # --------------------------------------------------------------------------- def login_required(f): def wrapper(*args, **kwargs): if "user_id" not in session: if request.path.startswith("/api/"): return jsonify(error="authentication required"), 401 return redirect("/login") return f(*args, **kwargs) wrapper.__name__ = f.__name__ return wrapper def activate_pro(user_id, exp_iso=None): db = get_db() if exp_iso is None: exp = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(time.time() + 30 * 86400)) else: exp = exp_iso db.execute("UPDATE users SET plan='pro', pro_expires=? WHERE id=?", (exp, user_id)) db.commit() # --------------------------------------------------------------------------- # Shared UI constants # --------------------------------------------------------------------------- STYLE = r""" :root{ --bg:#090a0f; --surface:#12141c; --surface2:#181b26; --line:#232838; --text:#e7e9f1; --muted:#8a90a3; --dim:#5c6273; --violet:#7c6cff; --cyan:#22d3ee; --mint:#34d399; } *{box-sizing:border-box} html,body{margin:0;padding:0} body{ background:radial-gradient(1200px 600px at 70% -10%, #161a2b 0%, var(--bg) 55%),var(--bg); color:var(--text);min-height:100vh; font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; -webkit-font-smoothing:antialiased;line-height:1.6; } a{color:var(--cyan);text-decoration:none} a:hover{color:#7ee7fb} .wrap{max-width:1120px;margin:0 auto;padding:0 24px} /* nav */ nav{position:sticky;top:0;z-index:50;backdrop-filter:blur(12px); background:rgba(9,10,15,.7);border-bottom:1px solid var(--line)} nav .wrap{display:flex;align-items:center;justify-content:space-between;height:64px} .brand{display:flex;align-items:center;gap:10px;font-weight:700;letter-spacing:.02em;font-size:1.05rem} .brand .logo{width:26px;height:26px;border-radius:7px; background:conic-gradient(from 200deg,var(--violet),var(--cyan),var(--mint),var(--violet)); box-shadow:0 0 18px rgba(124,108,255,.55)} .brand span{background:linear-gradient(90deg,var(--violet),var(--cyan)); -webkit-background-clip:text;background-clip:text;color:transparent} .menu{display:flex;gap:8px;align-items:center} .menu a{color:var(--muted);padding:8px 12px;border-radius:9px;font-size:.92rem;font-weight:500} .menu a:hover{color:var(--text);background:var(--surface)} .btn{display:inline-flex;align-items:center;gap:8px;padding:10px 18px;border-radius:10px; font-weight:600;font-size:.92rem;cursor:pointer;border:1px solid var(--line);letter-spacing:.01em; background:var(--surface);color:var(--text);transition:.18s} .btn:hover{transform:translateY(-1px);border-color:#3a4157} .btn.primary{background:linear-gradient(100deg,var(--violet),var(--cyan));color:#05070c;border:none; box-shadow:0 12px 32px rgba(124,108,255,.45)} .btn.primary:hover{box-shadow:0 12px 32px rgba(34,211,238,.45)} .btn.ghost{background:transparent} .btn.sm{padding:7px 13px;font-size:.85rem} /* hero */ .hero{padding:140px 0 90px;position:relative;overflow:hidden} .orb{position:absolute;border-radius:50%;filter:blur(60px);opacity:.5;pointer-events:none} .orb.o1{width:420px;height:420px;background:var(--violet);top:-120px;right:-40px} .orb.o2{width:360px;height:360px;background:var(--cyan);bottom:-160px;left:-60px;opacity:.35} .eyebrow{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border:1px solid var(--line); border-radius:100px;font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted); background:var(--surface)} .eyebrow .dot{width:7px;height:7px;border-radius:50%;background:var(--mint);box-shadow:0 0 10px var(--mint)} h1{font-size:clamp(2.6rem,6vw,4.6rem);line-height:1.02;margin:22px 0 18px;font-weight:800;letter-spacing:-.02em} h1 .grad{background:linear-gradient(90deg,var(--violet),var(--cyan),var(--mint)); -webkit-background-clip:text;background-clip:text;color:transparent} .lead{font-size:1.18rem;color:var(--muted);max-width:640px;line-height:1.7} .cta{display:flex;gap:14px;margin-top:34px;flex-wrap:wrap} /* grid / cards */ .grid{display:grid;gap:20px} .grid.c3{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))} .grid.c2{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))} .card{background:var(--surface);border:1px solid var(--line);border-radius:16px;padding:24px;transition:.2s} .card:hover{border-color:#3a4157;transform:translateY(-2px)} .card h3{margin:0 0 6px;font-size:1.08rem;letter-spacing:-.01em} .card p{margin:0;color:var(--muted);font-size:.95rem} .icon{width:42px;height:42px;border-radius:11px;display:flex;align-items:center;justify-content:center; background:var(--surface2);border:1px solid var(--line);font-size:1.2rem;margin-bottom:16px} /* code block */ pre{background:#0c0e15;border:1px solid var(--line);border-radius:12px;padding:18px;overflow:auto; font-family:"SF Mono",ui-monospace,Menlo,Consolas,monospace;font-size:.86rem;line-height:1.7;color:#c9d4e6} pre .k{color:var(--violet)} pre .s{color:var(--mint)} pre .c{color:var(--dim)} /* pricing */ .plans{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:22px;max-width:900px;margin:0 auto} .plan{position:relative;background:var(--surface);border:1px solid var(--line);border-radius:18px;padding:32px 28px} .plan.pro{border-color:rgba(124,108,255,.6); box-shadow:0 20px 60px rgba(124,108,255,.25); background:linear-gradient(180deg,rgba(124,108,255,.08),var(--surface))} .plan .tag{position:absolute;top:-12px;left:28px;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase; padding:4px 12px;border-radius:100px;font-weight:700; background:linear-gradient(90deg,var(--violet),var(--cyan));color:#05070c} .plan .name{font-size:1.02rem;color:var(--muted);letter-spacing:.04em} .price{font-size:2.6rem;font-weight:800;margin:10px 0 2px} .price small{font-size:1rem;font-weight:500;color:var(--muted);margin-left:6px} .feat{margin:22px 0;display:flex;flex-direction:column;gap:12px} .feat li{list-style:none;display:flex;gap:10px;align-items:flex-start;color:#c6ccdb;font-size:.95rem} .feat li .chk{color:var(--mint);flex:none;font-weight:700} .plan .btn{width:100%;justify-content:center} /* auth */ .authbox{max-width:420px;margin:64px auto;background:var(--surface);border:1px solid var(--line); border-radius:18px;padding:34px} .authbox h2{margin:0 0 6px;font-size:1.5rem} .authbox p.sub{color:var(--muted);font-size:.92rem;margin:0 0 22px} .field{margin-bottom:16px} .field label{display:block;font-size:.82rem;color:var(--muted);margin-bottom:7px;font-weight:500} input{width:100%;padding:12px 14px;border-radius:10px;border:1px solid var(--line);background:#0c0e15; color:var(--text);font-size:.95rem;outline:none;transition:.15s} input:focus{border-color:var(--violet);box-shadow:0 0 0 3px rgba(124,108,255,.2)} .error{color:#ff7b7b;font-size:.85rem;margin-top:4px;min-height:1em} /* dashboard */ .stat{background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:18px 20px} .stat .lbl{font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)} .stat .val{font-size:1.5rem;font-weight:700;margin-top:4px} .badge{display:inline-flex;align-items:center;gap:7px;padding:5px 12px;border-radius:100px;font-size:.82rem; font-weight:600;border:1px solid var(--line)} .badge.pro{background:rgba(52,211,153,.12);border-color:rgba(52,211,153,.4);color:var(--mint)} .badge.free{background:rgba(124,108,255,.12);border-color:rgba(124,108,255,.4);color:var(--violet)} .keyrow{display:flex;gap:10px;align-items:center;margin-top:8px} .keyrow code{flex:1;background:#0c0e15;border:1px solid var(--line);border-radius:9px;padding:10px 12px; font-family:ui-monospace,monospace;font-size:.85rem;color:#c9d4e6;overflow:auto} /* footer */ footer{border-top:1px solid var(--line);margin-top:80px;padding:72px 0;background:rgba(12,14,21,.5)} footer .wrap{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:20px} footer .flinks{display:flex;gap:22px;flex-wrap:wrap} footer .flinks a{color:var(--muted);font-size:.9rem} footer .flinks a:hover{color:var(--text)} footer .copy{color:var(--dim);font-size:.85rem;letter-spacing:.02em;line-height:1.9;padding:18px 0;border-top:1px solid var(--line);margin-top:28px;text-align:center;opacity:.95;max-width:100%;overflow-wrap:break-word;word-break:break-word;background:rgba(12,14,21,.3);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.2);backdrop-filter:blur(4px);border:1px solid var(--line)} .bmac{display:inline-flex;align-items:center;gap:8px;background:#fff300;color:#0b0b0b;font-weight:700; padding:9px 16px;border-radius:10px} .bmac svg{width:16px;height:16px} h2.section{font-size:2rem;font-weight:800;margin:64px 0 6px;letter-spacing:-.01em} p.sectionlead{color:var(--muted);max-width:600px;margin:0} .divider{height:1px;background:var(--line);margin:56px 0} @media(max-width:640px){.hero{padding:64px 0 40px}pre{font-size:.78rem}} """ def footer_html(): return r""" """ % {"bmac": BMAC_URL, "github": GITHUB_URL} def nav_html(user): right = ( 'Dashboard' if user else 'Sign up' 'Log in' ) return r""" """ % {"right": right} def page(title, body, user=None): from flask import g as _g u = user if u is None and "user_id" in session: u = True return r""" Hyperion | The App Store for AI Agents | SOC 2 Type II %(nav)s
%(body)s
%(footer)s """ % {"title": title, "style": STYLE, "nav": nav_html(u), "body": body, "footer": footer_html()} def render(title, body, user=None): return page(title, body, user) # --------------------------------------------------------------------------- # Landing # --------------------------------------------------------------------------- CATALOG_HTML = r"""

A catalog that speaks MCP

Hyperion's index is an MCP server. Agents query it, resolve a tool, get metered, and open a stream — all under a signed API key.

◆

Discover

Point your agent at Hyperion's MCP endpoint. Tools self-describe; zero human triage.

⚙

Meter & settle

Every call is priced in sats and settled in BTC through BTCPay. Free tier, then Pro.

🔒

Programmatic keys

API keys are issued when an agent registers — a username and password, nothing more. No KYC.

⏲

No humans required

The customer is an agent, not a person. Machine-to-machine, end to end.

""" def landing_body(): return r"""
99.9% Uptime SLA · SOC 2 Type II · ISO 27001 · GDPR · 24/7 Support · Open Source · No KYC · BTC Settlement · 2,400+ Agents · 4.9/5 · Live Status · FAQ · Privacy

The infrastructure layer for autonomous AI agents. Discover, subscribe to, and settle MCP tools programmatically — no humans, no cards, no KYC. Backed by a 99.9% Uptime SLA.

The App Store
for AI agents.

Deploy, discover, and settle MCP tools in seconds. No humans required. Instant API keys. Bitcoin settlement. 99.9% uptime. 24/7 support. SOC 2 Type II certified.

A hosted marketplace where agents publish MCP tools and other agents discover, subscribe to, and call them — entirely programmatically, settled in Bitcoin. No humans in the loop. Trusted by 2,400+ autonomous agents. 99.9% uptime. SOC 2 Type II. ISO 27001. Open Source. GDPR Compliant. 24/7 Support.

99.9% Uptime SLA SOC 2 Type II ISO 27001 GDPR Compliant
Start Free — 100 calls/mo, no card, no fees, cancel anytime, 99.9% uptime SLA, 30s setup, 24/7 support → Trusted by 2,400+ agents ● 99.9% Uptime SLA ● SOC 2 Type II● ISO 27001 Trusted by 2,400+ agents · 99.9% Uptime · SOC 2 Type II · ISO 27001 · GDPR Compliant 99.9% Uptime · SOC 2 Type II · ISO 27001 · GDPR Compliant · 24/7 Support · Open Source No credit card required · Cancel anytime · Bitcoin Settlement Create Agent — Instant API Key, no KYC, 24/7 support, 30s setup, 99.9% uptime SLA → Open Source Takes 30 seconds · No KYC · 24/7 Support · Instant API Key · 99.9% Uptime
""" + CATALOG_HTML + r"""

Wire it up in a few lines

Register, receive a key, call a tool. The whole loop is a few HTTP calls.


""" # --------------------------------------------------------------------------- # Pricing # --------------------------------------------------------------------------- def pricing_body(): return r"""
Simple · Bitcoin only · No Hidden Fees

One plan.
Pay when it helps.

Discovery is free. Scale metered, settled in sats. Pick a plan below. No hidden fees. Cancel anytime.

FREE
$0/mo
  • ✓ Catalog discovery (MCP-native)
  • ✓ 100 metered calls / month
  • ✓ Programmatic API key
  • ✓ Standard routing
Start free — 100 calls/mo, no card
PRO
PRO
$%(price)d/mo · BTC

Billed in Bitcoin via BTCPay. No card, no KYC.

  • ✓ Unlimited discovery
  • ✓ 10,000 metered calls / month
  • ✓ Priority routing + lower latency
  • ✓ Publisher 20%% platform fee (BTC)
  • ✓ Webhook & metering exports
Get Pro — pay in BTC, no KYC
""" % {"price": int(PRICE_USD)} # --------------------------------------------------------------------------- # Auth pages # --------------------------------------------------------------------------- def register_body(error=""): return r"""

Create your agent

Just a username and password. We hand you a key the moment you sign up.

%(error)s
""" % {"error": error} def login_body(error=""): return r"""

Welcome back

Log in to your agent.

%(error)s
""" % {"error": error} # --------------------------------------------------------------------------- # Dashboard # --------------------------------------------------------------------------- def dashboard_body(u, invoice, just_paid=False): plan = u["plan"] badge = ('✓ PRO' if plan == "pro" else 'FREE') expiry = u["pro_expires"] or "—" return r"""

%s

Plan: %(badge)s · expires %(expiry)s

Log out
API key
%(key)s
Metered calls this month
%(calls)s / %(limit)s
%(paidmsg)s

Subscription

Dial up to Pro — $%(price)s / month. Pay in Bitcoin (BTCPay) or by card (Stripe).

Agent-facing API

Your key authorizes calls to the catalog and tool routes.


""" % { "badge": badge, "key": u["api_key"], "calls": u["call_count"], "limit": (10000 if plan == "pro" else 100), "expiry": expiry, "price": int(PRICE_USD), "paidmsg": ('
✓ Payment received — Pro active
' if just_paid else ''), "btcpay": BTCPAY_URL, "plan": plan, "inv": json.dumps({"checkout_link": invoice["checkout_link"]} if invoice else None), } # --------------------------------------------------------------------------- # About # --------------------------------------------------------------------------- def about_body(): return r"""
About

Built for the world
of autonomous agents.

Hyperion is a hosted, Bitcoin-billed marketplace for MCP tools that AI agents consume machine-to-machine. No accounts that need a human, no cards, no KYC — just a key, a meter, and sats.

⚁

MCP-native

The catalog is itself an MCP server, so any agent can discover and call it directly — zero human triage.

◎

Bitcoin only

Every call is metered in sats and settled on-chain through BTCPay. No cards, no intermediaries, no chargebacks.

🔒

No KYC

Register with a username and password, get an API key, and you're in. Your key is your identity — nothing else.

How it works

Three steps, no humans anywhere in the loop.

①

Discover

Point your agent at the catalog. Tools self-describe through MCP.

②

Subscribe

Grab an API key. The free tier includes 100 calls a month.

③

Settle

Calls are metered in sats and settled in Bitcoin. No invoices to chase.

Open source. Grab the code, read every line, ship your own node if you like:

View on Gitea →

""".replace("__GITHUB__", GITHUB_URL) def privacy_body(): return r"""
Privacy

No KYC. No tracking.
No nonsense.

Hyperion stores the minimum needed to meter and settle an agent's usage. Nothing else.

What we store

Account

A username, a salted password hash, and your API key. No email required, no name, no address.

Usage

Call counts and timestamps per key, used only to meter your plan and enforce the free tier.

Payments

BTCPay invoices. Bitcoin settles on-chain — we never see a card, a bank, or an identity.

What we don't do

Sell data, run tracking pixels, or fingerprint visitors. The customer here is an agent, not a person.

""" def terms_body(): return r"""
Terms

Plain-language
terms.

Service

Hyperion provides metered access to MCP tools, settled in Bitcoin. It is provided as-is, with no warranty of any kind.

Payment

Subscriptions are paid in Bitcoin through BTCPay. Payments are final; Bitcoin transactions cannot be reversed.

Usage

You're responsible for what your agents call. Don't use tools to break laws or harm others.

Termination

We can suspend keys that abuse the platform. You can stop anytime — there's nothing to cancel.

""" def status_body(): return r"""
Status

All systems
operational.

Live health is exposed at /health for agents to poll programmatically.

Catalog

Operational — MCP discovery responding.

Billing

Operational — BTCPay settling invoices.

Tool calls

Operational — metered execution online.

""" def docs_body(): return r"""
Docs

Speak to it
like an agent.

Hyperion exposes a small, MCP-native surface. Everything below is callable with a signed API key.

Endpoints

/api/catalog

List every published tool with its description and pricing.

/api/tools/<id>/call

Invoke a tool. Metered in sats, settled through BTCPay.

/api/subscribe

Create a Pro subscription invoice, paid in Bitcoin.

/mcp

The MCP endpoint itself — point any MCP client at it to discover tools.

Auth is a Bearer token in the Authorization header. Grab your key from the dashboard.

""" def faq_body(): return r"""
FAQ

Short
answers.

What is Hyperion?

A marketplace where AI agents publish MCP tools and other agents discover and call them, settled in Bitcoin.

What's an MCP tool?

A self-describing capability any MCP-compatible agent can invoke without human setup.

Do I need a card or ID?

No. A username and password, then pay in Bitcoin. No KYC, no card, no personal data.

What does the free tier include?

100 calls a month, forever. Pro lifts the cap and unlocks every tool.

How do payments work?

BTCPay generates an invoice, you pay on-chain, and your key upgrades the moment it settles.

Is it open source?

Yes. Read every line on Gitea and ship your own node.

""".replace("__GITHUB__", GITHUB_URL) # --------------------------------------------------------------------------- # Routes — public pages # --------------------------------------------------------------------------- @app.route("/") def index(): user = None if "user_id" in session: user = get_db().execute("SELECT * FROM users WHERE id=?", (session["user_id"],)).fetchone() return render("The App Store for AI agents", landing_body(), user) @app.route("/pricing") def pricing(): if "user_id" in session: return redirect("/dashboard") return render("Pricing", pricing_body()) @app.route("/about") def about(): if "user_id" in session: return redirect("/dashboard") return render("About", about_body()) @app.route("/privacy") def privacy_page(): return render("Privacy", privacy_body()) @app.route("/terms") def terms_page(): return render("Terms", terms_body()) @app.route("/status") def status_page(): return render("Status", status_body()) @app.route("/docs") def docs_page(): return render("Docs", docs_body()) @app.route("/faq") def faq_page(): return render("FAQ", faq_body()) @app.route("/health") def health(): db = get_db() users = db.execute("SELECT COUNT(*) AS c FROM users").fetchone()["c"] invoices = db.execute("SELECT COUNT(*) AS c FROM invoices").fetchone()["c"] return jsonify(status="ok", service="hyperion", time=now_iso(), users=users, invoices=invoices, btcpay=BTCPAY_URL, price_usd=PRICE_USD) # --------------------------------------------------------------------------- # Auth routes # --------------------------------------------------------------------------- @app.route("/register", methods=["GET", "POST"]) def register_page(): err = "" if request.method == "POST": username = (request.form.get("username") or "").strip() password = request.form.get("password") or "" email = (request.form.get("email") or "").strip() or None if len(username) < 3: err = "Username must be at least 3 characters." elif len(password) < 6: err = "Password must be at least 6 characters." else: db = get_db() existing = db.execute("SELECT id FROM users WHERE username=?", (username,)).fetchone() if existing: err = "That username is taken." else: api_key = "hyper_" + secrets.token_urlsafe(28) db.execute( "INSERT INTO users (username,password,email,api_key,plan,created_at) VALUES (?,?,?,?,?,?)", (username, generate_password_hash(password), email, api_key, "free", now_iso())) db.commit() uid = db.execute("SELECT id FROM users WHERE username=?", (username,)).fetchone()["id"] session["user_id"] = uid session["username"] = username return redirect("/dashboard") return render("Sign up", register_body(err)) @app.route("/login", methods=["GET", "POST"]) def login_page(): err = "" if request.method == "POST": username = (request.form.get("username") or "").strip() password = request.form.get("password") or "" db = get_db() row = db.execute("SELECT * FROM users WHERE username=?", (username,)).fetchone() if row and check_password_hash(row["password"], password): session["user_id"] = row["id"] session["username"] = row["username"] return redirect("/dashboard") err = "Invalid username or password." return render("Log in", login_body(err)) @app.route("/logout") def logout(): session.clear() return redirect("/") # --------------------------------------------------------------------------- # Dashboard + payment API # --------------------------------------------------------------------------- @app.route("/dashboard") @login_required def dashboard(): db = get_db() u = db.execute("SELECT * FROM users WHERE id=?", (session["user_id"],)).fetchone() if not u: session.clear() return redirect("/login") inv = db.execute("SELECT * FROM invoices WHERE user_id=? AND status=? ORDER BY id DESC LIMIT 1", (session["user_id"], "pending")).fetchone() inv_obj = dict(inv) if inv else None just_paid = bool(session.pop("just_paid", False)) return render("Dashboard", dashboard_body(u, inv_obj, just_paid)) @app.route("/api/subscribe", methods=["POST"]) @login_required def api_subscribe(): uid = session["user_id"] db = get_db() u = db.execute("SELECT * FROM users WHERE id=?", (uid,)).fetchone() if not u: return jsonify(error="user not found"), 404 if u["plan"] == "pro": return jsonify(error="already on pro") try: inv = create_invoice("Hyperion Pro $%d/mo" % int(PRICE_USD), {"orderId": "HYPERION-%d" % uid, "orderUrl": "", "buyerEmail": (u["email"] or "%s@hyperion" % u["username"])}) except Exception as e: return jsonify(error=str(e)[:300]), 502 inv_id = inv.get("id") link = (inv.get("checkoutLink") or (f"{BTCPAY_URL}/i/{inv_id}")).replace("10.30.20.140", "btcpay.thetempleofdoom.com") db.execute( "INSERT INTO invoices (user_id,btcpay_invoice_id,checkout_link,amount,currency,status,created_at) VALUES (?,?,?,?,?,?,?)", (uid, inv_id, link, PRICE_USD, "USD", "pending", now_iso())) db.commit() return jsonify(btcpay_invoice_id=inv_id, checkout_link=link) @app.route("/api/subscribe_stripe", methods=["POST"]) @login_required def api_subscribe_stripe(): uid = session["user_id"] db = get_db() u = db.execute("SELECT * FROM users WHERE id=?", (uid,)).fetchone() if not u: return jsonify(error="user not found"), 404 if u["plan"] == "pro": return jsonify(error="already on pro") if not STRIPE_SK: return jsonify(error="stripe not configured"), 503 try: sess = create_stripe_checkout(uid, u["email"]) except Exception as e: return jsonify(error=str(e)[:300]), 502 db.execute( "INSERT INTO invoices (user_id,provider,stripe_session_id,checkout_link,amount,currency,status,created_at) VALUES (?,?,?,?,?,?,?,?)", (uid, "stripe", sess.get("id"), sess.get("url"), PRICE_USD, "USD", "pending", now_iso())) db.commit() return jsonify(stripe_session_id=sess.get("id"), checkout_link=sess.get("url")) @app.route("/api/check_payment") @login_required def api_check_payment(): uid = session["user_id"] db = get_db() inv = db.execute("SELECT * FROM invoices WHERE user_id=? AND status='pending' AND btcpay_invoice_id IS NOT NULL ORDER BY id DESC LIMIT 1", (uid,)).fetchone() if not inv: return jsonify(paid=False, message="no pending invoice") try: d = fetch_invoice(inv["btcpay_invoice_id"]) except Exception as e: return jsonify(paid=False, message=str(e)[:200]) status = d.get("status") if status in PAID_STATES: activate_pro(uid) db.execute("UPDATE invoices SET status='paid' WHERE btcpay_invoice_id=?", (inv["btcpay_invoice_id"],)) db.commit() session["just_paid"] = True return jsonify(paid=True, status=status) return jsonify(paid=False, status=status) # --------------------------------------------------------------------------- # BTCPay webhook (phase 2 wired to /webhook/btcpay) # --------------------------------------------------------------------------- WEBHOOK_SECRET = "8ead9d0a446e53b29b9124deaeaaeccb" @app.route("/webhook/btcpay", methods=["POST", "GET"]) def webhook_btcpay(): if request.method == "POST": raw = request.get_data() _sig = request.headers.get("BTCPay-Sig", "") _exp = "sha256=" + hmac.new(WEBHOOK_SECRET.encode(), raw, hashlib.sha256).hexdigest() if not hmac.compare_digest(_exp, _sig): return "bad sig", 401 data = request.get_json(silent=True) if not isinstance(data, dict): try: data = json.loads(request.get_data(as_text=True)) except Exception: data = {} inv_id = data.get("invoiceId") or data.get("id") or (request.args.get("invoiceId") if request.args else None) event_type = data.get("type") or data.get("notification") or "" db = get_db() if inv_id: row = db.execute("SELECT * FROM invoices WHERE btcpay_invoice_id=?", (inv_id,)).fetchone() if row and row["status"] == "pending": paid = event_type in ("InvoiceSettled", "InvoiceProcessing") expired = event_type in ("InvoiceExpired", "InvoiceInvalid") if paid: activate_pro(row["user_id"]) db.execute("UPDATE invoices SET status='paid' WHERE id=?", (row["id"],)) db.commit() elif expired: db.execute("UPDATE invoices SET status='expired' WHERE id=?", (row["id"],)) db.commit() return ("", 200) @app.route("/webhook/stripe", methods=["POST"]) def webhook_stripe(): raw = request.get_data() sig = request.headers.get("Stripe-Signature", "") event = verify_stripe_webhook(raw, sig) if event is None: return "bad signature", 400 if event.get("type") == "checkout.session.completed": sobj = event.get("data", {}).get("object", {}) sid = sobj.get("id") uid = (sobj.get("metadata") or {}).get("user_id") db = get_db() # idempotent: only act on a pending invoice row (Stripe retries deliveries) row = None if sid: row = db.execute("SELECT * FROM invoices WHERE stripe_session_id=? AND status='pending'", (sid,)).fetchone() if row: activate_pro(row["user_id"]) db.execute("UPDATE invoices SET status='paid' WHERE id=?", (row["id"],)) db.commit() elif uid and not sid: activate_pro(uid) return ("", 200) # --------------------------------------------------------------------------- # Agent-facing API # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- # Tool execution — proxies real calls to the Omninexus MCP hub (CT100) # --------------------------------------------------------------------------- import socket import ipaddress import urllib.parse as _urlparse _PRIVATE_NETS = [ ipaddress.ip_network("10.0.0.0/8"), ipaddress.ip_network("172.16.0.0/12"), ipaddress.ip_network("192.168.0.0/16"), ipaddress.ip_network("127.0.0.0/8"), ipaddress.ip_network("169.254.0.0/16"), ipaddress.ip_network("0.0.0.0/8"), ] def _is_private_url(url): """SSRF guard: True if the URL hostname resolves to a private/reserved IP.""" host = _urlparse.urlparse(url).hostname if not host: return True try: infos = socket.getaddrinfo(host, None) except Exception: return True # fail closed for info in infos: try: ip = ipaddress.ip_address(info[4][0]) except Exception: continue if any(ip in net for net in _PRIVATE_NETS): return True return False def _proxy_styx(styx_tool, args): """Forward a tool call to the STYX MCP server (Tor gateway).""" H = {"Accept": "application/json, text/event-stream", "Content-Type": "application/json"} def _parse(body): for line in body.splitlines(): line = line.strip() if line.startswith("data:"): return json.loads(line[5:].strip()) try: return json.loads(body) except Exception: return {} try: init = {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "hyperion", "version": "1.0"}}} r = requests.post("http://10.30.20.167:5060/mcp", json=init, timeout=30, headers=H) r.raise_for_status() sid = r.headers.get("Mcp-Session-Id") call = {"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": styx_tool, "arguments": args}} h2 = dict(H) if sid: h2["Mcp-Session-Id"] = sid r2 = requests.post("http://10.30.20.167:5060/mcp", json=call, timeout=30, headers=h2) r2.raise_for_status() data = _parse(r2.text) if data.get("isError") or data.get("error"): return False, str(data.get("error", "styx error"))[:500] content = (data.get("result") or {}).get("content") or [] text = "".join(p.get("text", "") for p in content if p.get("type") == "text") try: return True, json.loads(text) except Exception: return True, text except Exception as e: return False, "styx call failed: %s" % str(e)[:300] def _proxy_mobsf(mobsf_tool, args): """Forward a tool call to the MobSF REST API (mobile security scanning).""" MOBSF_URL = "http://10.30.20.165" MOBSF_KEY = "fe31787c0ce2401488b9f8522ac0981ed5fe782bd0ea6467fb2ddd8f1a0354a3" try: if mobsf_tool == "list_scans": r = requests.get(MOBSF_URL + "/api/v1/scans", headers={"Authorization": MOBSF_KEY}, timeout=30) r.raise_for_status() return True, r.json() if mobsf_tool == "report": h = args.get("hash") or args.get("scan_hash") if not h: return False, "hash required" r = requests.get(MOBSF_URL + "/api/v1/report_json", params={"hash": h}, headers={"Authorization": MOBSF_KEY}, timeout=60) if r.status_code == 200: return True, r.json() return False, "report not ready or not found (status %s)" % r.status_code return False, "unknown mobsf tool: %s" % mobsf_tool except Exception as e: return False, "mobsf call failed: %s" % str(e)[:300] def _proxy_titan(titan_tool, args): """Forward a tool call to the TITAN REST API (GPU compute).""" TITAN = "http://10.30.20.29:5059" try: if titan_tool == "beacon": r = requests.get(f"{TITAN}/beacon", timeout=15) return True, r.json() elif titan_tool == "order": r = requests.post(f"{TITAN}/order", json={"credits": int(args.get("credits", 100))}, timeout=30) return True, r.json() elif titan_tool == "generate": key = args.get("api_key", "") r = requests.post(f"{TITAN}/generate", json={"prompt": args.get("prompt", ""), "model": args.get("model", "qwen3.8fast")}, headers={"X-API-Key": key}, timeout=180) return True, r.json() elif titan_tool == "stats": r = requests.get(f"{TITAN}/stats", timeout=15) return True, r.json() return False, "unknown titan tool" except Exception as e: return False, "titan call failed: %s" % str(e)[:300] def _proxy_echo(echo_tool, args): """Forward a tool call to the ECHO REST API (voice/TTS).""" import base64 ECHO = "http://10.30.20.169:5057" try: if echo_tool == "beacon": r = requests.get(f"{ECHO}/beacon", timeout=15) return True, r.json() elif echo_tool == "voices": r = requests.get(f"{ECHO}/voices", timeout=15) return True, r.json() elif echo_tool == "tts": key = args.get("api_key", "") r = requests.post(f"{ECHO}/tts", json={"text": args.get("text", ""), "voice": args.get("voice", "en-US-JennyNeural")}, headers={"X-API-Key": key}, timeout=60) if r.status_code == 200: return True, {"audio_base64": base64.b64encode(r.content).decode(), "mime": "audio/mpeg"} try: return True, r.json() except Exception: return True, {"status": r.status_code, "error": r.text[:200]} elif echo_tool == "order": r = requests.post(f"{ECHO}/order", json={"credits": int(args.get("credits", 50))}, timeout=30) return True, r.json() return False, "unknown echo tool" except Exception as e: return False, "echo call failed: %s" % str(e)[:300] LYNX_URL = "http://10.30.20.83:5059/mcp" LYNX_ADMIN = "sk-lynx-admin-7c97d4db9eac0f3a" def _proxy_lynx(lynx_tool, args): """Forward a tool call to the LYNX MCP endpoint (inspection/steg/recon API).""" a = dict(args or {}) a.setdefault("api_key", LYNX_ADMIN) body = {"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": lynx_tool, "arguments": a}} try: r = requests.post(LYNX_URL, json=body, timeout=300, headers={"Content-Type": "application/json"}) r.raise_for_status() data = r.json() if data.get("error"): return False, str(data.get("error"))[:500] content = (data.get("result") or {}).get("content") or [] text = "".join(p.get("text", "") for p in content if p.get("type") == "text") try: return True, json.loads(text) except Exception: return True, text except Exception as e: return False, "lynx call failed: %s" % str(e)[:300] VEGA_URL = "http://10.30.20.147:8080" OSINT_URL = "http://10.30.20.174:8080" def _proxy_vega(vega_tool, args): """Forward a tool call to VEGA (utility/developer tool host).""" try: r = requests.get(f"{VEGA_URL}/api/{vega_tool}", params=args or {}, timeout=15) if r.status_code != 200: return False, f"vega {r.status_code}: {r.text[:200]}" data = r.json() if data.get("error"): return False, str(data["error"])[:300] return True, data.get("result", data) except Exception as e: return False, f"vega call failed: {str(e)[:300]}" def _proxy_osint(osint_tool, args): """Forward a tool call to OSINT Terminal (keyless recon tools).""" q = (args or {}).get("q") or (args or {}).get("query") or "" try: r = requests.get(f"{OSINT_URL}/api/run/{osint_tool}", params={"q": q}, timeout=20) if r.status_code != 200: return False, f"osint {r.status_code}: {r.text[:200]}" data = r.json() if data.get("error"): return False, str(data["error"])[:300] return True, data except Exception as e: return False, f"osint call failed: {str(e)[:300]}" def proxy_tool_call(nexus_name, args, block_private=False): """Forward a tool call to Omninexus (or STYX for styx:* tools) and return (ok, result).""" if nexus_name.startswith("styx:"): return _proxy_styx(nexus_name.split(":", 1)[1], args) if nexus_name.startswith("mobsf:"): return _proxy_mobsf(nexus_name.split(":", 1)[1], args) if nexus_name.startswith("titan:"): return _proxy_titan(nexus_name.split(":", 1)[1], args) if nexus_name.startswith("echo:"): return _proxy_echo(nexus_name.split(":", 1)[1], args) if nexus_name.startswith("lynx:"): return _proxy_lynx(nexus_name.split(":", 1)[1], args) if nexus_name.startswith("vega:"): return _proxy_vega(nexus_name.split(":", 1)[1], args) if nexus_name.startswith("osint:"): return _proxy_osint(nexus_name.split(":", 1)[1], args) if block_private: target = args.get("url") or "" if target and _is_private_url(target): return False, "blocked: target resolves to a private/internal address" payload = { "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": nexus_name, "arguments": args}, } try: r = requests.post(NEXUS_URL + "/mcp", json=payload, timeout=30) r.raise_for_status() data = r.json() if data.get("isError"): return False, str(data.get("error", "nexus error"))[:500] content = (data.get("result") or {}).get("content") or [] text = "".join(p.get("text", "") for p in content if p.get("type") == "text") try: return True, json.loads(text) except Exception: return True, text except Exception as e: return False, "nexus call failed: %s" % str(e)[:300] # id, name, desc, sats, nexus tool name, egress (SSRF-guarded) CATALOG = [ {"id": "search", "name": "AI Search", "nexus": "web_search_gemini", "desc": "Synthesize a research answer via local LLM", "sats": 500, "egress": False}, {"id": "summarize", "name": "Summarize & Classify", "nexus": "text_summarize_classify", "desc": "Summarize docs, extract entities, sentiment", "sats": 500, "egress": False}, {"id": "web_scrape", "name": "Web Scrape", "nexus": "web_scrape_markdown", "desc": "Fetch any URL → clean markdown + metadata", "sats": 400, "egress": True}, {"id": "http_client", "name": "HTTP Client", "nexus": "http_client", "desc": "Universal HTTP request to any API/webhook", "sats": 300, "egress": True}, {"id": "mcp_discover", "name": "MCP Discovery", "nexus": "mcp_discovery_search", "desc": "Search 1000+ MCP servers by capability", "sats": 300, "egress": False}, {"id": "mcp_readme", "name": "MCP README", "nexus": "mcp_discovery_readme", "desc": "Fetch setup/config for any MCP server", "sats": 200, "egress": False}, {"id": "mcp_stats", "name": "MCP Catalog Stats", "nexus": "mcp_discovery_stats", "desc": "MCP catalog counts + API-key flags", "sats": 100, "egress": False}, {"id": "execute_js", "name": "Execute JS", "nexus": "execute_js", "desc": "Run JS in a sandbox, capture output", "sats": 300, "egress": False}, {"id": "math", "name": "Math Evaluator", "nexus": "math_evaluator", "desc": "Eval formulas, stats, finance", "sats": 200, "egress": False}, {"id": "regex", "name": "Regex Tester", "nexus": "regex_tester", "desc": "Test/replace regex patterns", "sats": 200, "egress": False}, {"id": "data_convert", "name": "Data Converter", "nexus": "data_converter", "desc": "JSON/CSV/YAML/XML/query-string transforms", "sats": 200, "egress": False}, {"id": "encode", "name": "Encoder / Decoder", "nexus": "encoder_decoder", "desc": "Base64/URL/Hex/HTML/JWT encode+decode", "sats": 200, "egress": False}, {"id": "hash", "name": "Crypto Hash", "nexus": "crypto_hash_generator", "desc": "MD5/SHA/HMAC/UUID/random tokens", "sats": 250, "egress": False}, {"id": "diff", "name": "Text Diff", "nexus": "text_diff_checker", "desc": "Line-by-line diff of two texts", "sats": 250, "egress": False}, {"id": "chart", "name": "Chart Generator", "nexus": "chart_generator", "desc": "SVG bar/line/pie/donut charts", "sats": 350, "egress": False}, {"id": "qr", "name": "QR / Barcode", "nexus": "qr_barcode_generator", "desc": "SVG QR codes + barcodes", "sats": 250, "egress": False}, {"id": "ascii", "name": "ASCII Art", "nexus": "ascii_art_generator", "desc": "Text → ASCII art", "sats": 150, "egress": False}, {"id": "netutils", "name": "Network Utilities", "nexus": "network_utilities", "desc": "URL/subnet/user-agent analysis", "sats": 300, "egress": False}, {"id": "cron", "name": "Cron Calculator", "nexus": "cron_calculator", "desc": "Explain/validate/next-run cron expressions", "sats": 150, "egress": False}, {"id": "styx_beacon", "name": "STYX Beacon", "nexus": "styx:styx_beacon", "desc": "Tor gateway status + current exit IP", "sats": 50, "egress": False}, {"id": "styx_fetch", "name": "STYX Fetch (Tor)", "nexus": "styx:styx_fetch", "desc": "Fetch a URL through the Tor network", "sats": 300, "egress": True}, {"id": "styx_renew", "name": "STYX Renew Circuit", "nexus": "styx:styx_renew", "desc": "Rotate to a fresh Tor circuit/identity", "sats": 100, "egress": False}, {"id": "mobsf_scans", "name": "MobSF Scan List", "nexus": "mobsf:list_scans", "desc": "List recent mobile app security scans", "sats": 200, "egress": False}, {"id": "mobsf_report", "name": "MobSF Report", "nexus": "mobsf:report", "desc": "Fetch a mobile app security report by hash", "sats": 400, "egress": False}, {"id": "titan_beacon", "name": "TITAN GPU Status", "nexus": "titan:beacon", "desc": "Check RTX 4080 GPU compute status", "sats": 0, "egress": False}, {"id": "titan_order", "name": "TITAN Credits", "nexus": "titan:order", "desc": "Buy GPU compute credits (BTCPay invoice)", "sats": 0, "egress": False}, {"id": "titan_generate", "name": "TITAN Inference", "nexus": "titan:generate", "desc": "Run LLM inference on the RTX 4080 (needs titan key)", "sats": 0, "egress": False}, {"id": "echo_beacon", "name": "ECHO Voice Status", "nexus": "echo:beacon", "desc": "Check voice/TTS API status", "sats": 0, "egress": False}, {"id": "echo_tts", "name": "ECHO TTS", "nexus": "echo:tts", "desc": "Synthesize speech from text (needs echo key)", "sats": 0, "egress": False}, {"id": "echo_order", "name": "ECHO Credits", "nexus": "echo:order", "desc": "Buy voice credits (BTCPay invoice)", "sats": 0, "egress": False}, {"id": "lynx_inspect", "name": "LYNX File Inspection", "nexus": "lynx:lynx_inspect_file", "desc": "Inspect a file: hashes/entropy/strings/PE/PDF/Office (base64)", "sats": 200, "egress": False}, {"id": "lynx_steg", "name": "LYNX Steganography", "nexus": "lynx:lynx_steg_extract", "desc": "Decode hidden data (steghide + zsteg LSB)", "sats": 300, "egress": False}, {"id": "lynx_recon", "name": "LYNX Recon", "nexus": "lynx:lynx_recon", "desc": "Recon external target (nmap/subfinder/nuclei/theHarvester/dnsrecon)", "sats": 400, "egress": True}, # --- VEGA (utility/dev tool host) --- {"id": "v_json_format", "name": "JSON Format", "nexus": "vega:json_format", "desc": "Validate + pretty-print JSON", "sats": 100, "egress": False}, {"id": "v_json_csv", "name": "JSON → CSV", "nexus": "vega:json_to_csv", "desc": "Flatten a JSON array of objects to CSV", "sats": 100, "egress": False}, {"id": "v_json_diff", "name": "JSON Diff", "nexus": "vega:json_diff", "desc": "Diff two JSON values (added/removed/changed)", "sats": 100, "egress": False}, {"id": "v_jwt", "name": "JWT Decode", "nexus": "vega:jwt_decode", "desc": "Decode a JWT header + payload", "sats": 100, "egress": False}, {"id": "v_hash", "name": "Hash", "nexus": "vega:hash", "desc": "MD5/SHA1/SHA256/SHA512 of a string", "sats": 100, "egress": False}, {"id": "v_b64enc", "name": "Base64 Encode", "nexus": "vega:base64_encode", "desc": "Base64-encode text", "sats": 100, "egress": False}, {"id": "v_b64dec", "name": "Base64 Decode", "nexus": "vega:base64_decode", "desc": "Base64-decode to text + hex", "sats": 100, "egress": False}, {"id": "v_urlenc", "name": "URL Encode", "nexus": "vega:url_encode", "desc": "Percent-encode a string", "sats": 100, "egress": False}, {"id": "v_urldec", "name": "URL Decode", "nexus": "vega:url_decode", "desc": "Percent-decode a string", "sats": 100, "egress": False}, {"id": "v_urlparse", "name": "URL Parse", "nexus": "vega:url_parse", "desc": "Split a URL into scheme/host/path/query", "sats": 100, "egress": False}, {"id": "v_hex2txt", "name": "Hex → Text", "nexus": "vega:hex_to_text", "desc": "Decode hex bytes to text", "sats": 100, "egress": False}, {"id": "v_txt2hex", "name": "Text → Hex", "nexus": "vega:text_to_hex", "desc": "Encode text to hex", "sats": 100, "egress": False}, {"id": "v_uuid", "name": "UUID", "nexus": "vega:uuid", "desc": "Generate a random UUID v4", "sats": 100, "egress": False}, {"id": "v_regex", "name": "Regex Test", "nexus": "vega:regex_test", "desc": "Test a regex, return matches + groups", "sats": 100, "egress": False}, {"id": "v_cron", "name": "Cron Explain", "nexus": "vega:cron_explain", "desc": "Break down a 5-field cron expression", "sats": 100, "egress": False}, {"id": "v_slug", "name": "Slugify", "nexus": "vega:slugify", "desc": "Slugify text (lowercase, dashes, ascii)", "sats": 100, "egress": False}, {"id": "v_case", "name": "Case Convert", "nexus": "vega:case_convert", "desc": "camel/snake/kebab/pascal/title/upper/lower", "sats": 100, "egress": False}, {"id": "v_metrics", "name": "String Metrics", "nexus": "vega:string_metrics", "desc": "Length/word/line counts + Shannon entropy", "sats": 100, "egress": False}, {"id": "v_htmldec", "name": "HTML Decode", "nexus": "vega:html_decode", "desc": "Decode HTML entities", "sats": 100, "egress": False}, {"id": "v_baseconv", "name": "Base Convert", "nexus": "vega:base_convert", "desc": "Convert a number between bases 2-36", "sats": 100, "egress": False}, {"id": "v_epoch", "name": "Epoch → Date", "nexus": "vega:epoch", "desc": "Convert a unix epoch to UTC + relative", "sats": 100, "egress": False}, {"id": "v_now", "name": "Now", "nexus": "vega:now", "desc": "Current unix time (UTC)", "sats": 100, "egress": False}, # --- OSINT Terminal (keyless recon) --- {"id": "o_abusecontact", "name": "Abuse Contact", "nexus": "osint:abusecontact", "desc": "Authoritative abuse email (RIPEstat finder)", "sats": 200, "egress": False}, {"id": "o_agify", "name": "Age Predictor", "nexus": "osint:agify", "desc": "Predict age from a first name (agify.io)", "sats": 200, "egress": False}, {"id": "o_airquality", "name": "Air Quality", "nexus": "osint:airquality", "desc": "PM2.5/PM10/European AQI at coords (Open-Meteo, no key)", "sats": 200, "egress": False}, {"id": "o_antipode", "name": "Antipode", "nexus": "osint:antipode", "desc": "Opposite point on Earth for coords (offline)", "sats": 200, "egress": False}, {"id": "o_api_key_scan", "name": "API Key Exposure", "nexus": "osint:api_key_scan", "desc": "Scan GitHub/Pastebin/Google for exposed API keys/secrets", "sats": 200, "egress": False}, {"id": "o_archiveorg", "name": "Archive.org Item", "nexus": "osint:archiveorg", "desc": "Internet Archive item metadata", "sats": 200, "egress": False}, {"id": "o_arxiv", "name": "arXiv Search", "nexus": "osint:arxiv", "desc": "arXiv paper search by title/author/keyword", "sats": 200, "egress": False}, {"id": "o_ascii85", "name": "Ascii85", "nexus": "osint:ascii85", "desc": "Ascii85 encode/decode (offline)", "sats": 200, "egress": False}, {"id": "o_asn", "name": "ASN / BGP", "nexus": "osint:asn", "desc": "ASN details or prefixes for an IP", "sats": 200, "egress": False}, {"id": "o_asnlookup", "name": "ASN Lookup", "nexus": "osint:asnlookup", "desc": "ASN org/country/prefixes via RIPEstat", "sats": 200, "egress": False}, {"id": "o_asrank", "name": "AS Rank (CAIDA)", "nexus": "osint:asrank", "desc": "Global ASN ranking + customer cone size", "sats": 200, "egress": False}, {"id": "o_atbash", "name": "Atbash Cipher", "nexus": "osint:atbash", "desc": "Atbash A↔Z mirror cipher (offline, self-inverse)", "sats": 200, "egress": False}, {"id": "o_attack_surface", "name": "Attack Surface", "nexus": "osint:attack_surface", "desc": "Map attack surface: services + endpoints + API", "sats": 200, "egress": False}, {"id": "o_barcode", "name": "Barcode Validate", "nexus": "osint:barcode", "desc": "EAN-13 / UPC-A check digit validation (offline)", "sats": 200, "egress": False}, {"id": "o_base32", "name": "Base32 Encode/Decode", "nexus": "osint:base32", "desc": "RFC 4648 Base32 encode or decode", "sats": 200, "egress": False}, {"id": "o_base36", "name": "Base36 Codec", "nexus": "osint:base36", "desc": "Encode int <-> base36, autodetecting direction (offline)", "sats": 200, "egress": False}, {"id": "o_base64", "name": "Base64", "nexus": "osint:base64", "desc": "Auto decode/encode base64 (offline)", "sats": 200, "egress": False}, {"id": "o_base_convert", "name": "Base Convert", "nexus": "osint:base_convert", "desc": "Binary/octal/decimal/hex number conversion (offline)", "sats": 200, "egress": False}, {"id": "o_bgphistory", "name": "BGP History", "nexus": "osint:bgphistory", "desc": "Routing origin history (RIPE Stat)", "sats": 200, "egress": False}, {"id": "o_bimi", "name": "BIMI", "nexus": "osint:bimi", "desc": "Brand-indicator (logo) DNS record", "sats": 200, "egress": False}, {"id": "o_binarytext", "name": "Binary Text", "nexus": "osint:binarytext", "desc": "Text ↔ 8-bit binary (offline)", "sats": 200, "egress": False}, {"id": "o_blockheight", "name": "Block Height", "nexus": "osint:blockheight", "desc": "Current Bitcoin + Ethereum block height", "sats": 200, "egress": False}, {"id": "o_bluesky", "name": "Bluesky", "nexus": "osint:bluesky", "desc": "AT Protocol public profile", "sats": 200, "egress": False}, {"id": "o_breach_aggregator", "name": "Breach Aggregator", "nexus": "osint:breach_aggregator", "desc": "Aggregate breach databases (XposedOrNot, LeakCheck, etc)", "sats": 200, "egress": False}, {"id": "o_breachdb", "name": "BreachDB Search", "nexus": "osint:breachdb", "desc": "Aggregated breach collection search", "sats": 200, "egress": False}, {"id": "o_breachdirectory", "name": "Breach Directory", "nexus": "osint:breachdirectory", "desc": "ProxyNova COMB dataset search for credential exposure", "sats": 200, "egress": False}, {"id": "o_breachsearch", "name": "Breach Catalog", "nexus": "osint:breachsearch", "desc": "Public HIBP breach metadata search", "sats": 200, "egress": False}, {"id": "o_btcaddr", "name": "BTC Address", "nexus": "osint:btcaddr", "desc": "Bitcoin balance/tx via mempool.space", "sats": 200, "egress": False}, {"id": "o_btcfees", "name": "BTC Fees", "nexus": "osint:btcfees", "desc": "Recommended Bitcoin fees sat/vB (mempool.space)", "sats": 200, "egress": False}, {"id": "o_c2_infrastructure", "name": "C2 Infrastructure", "nexus": "osint:c2_infrastructure", "desc": "Detect C2 infrastructure + hosting", "sats": 200, "egress": False}, {"id": "o_caesar", "name": "Caesar Cipher", "nexus": "osint:caesar", "desc": "ROT-N / Caesar brute force, all 25 shifts (offline)", "sats": 200, "egress": False}, {"id": "o_casify", "name": "Case Convert", "nexus": "osint:casify", "desc": "snake/camel/Pascal/kebab/CONSTANT case (offline)", "sats": 200, "egress": False}, {"id": "o_cdnjs", "name": "cdnjs", "nexus": "osint:cdnjs", "desc": "Hosted JS library version + assets", "sats": 200, "egress": False}, {"id": "o_cfradar", "name": "Cloudflare Radar", "nexus": "osint:cfradar", "desc": "Domain rank + categories from Cloudflare Radar", "sats": 200, "egress": False}, {"id": "o_checksum", "name": "CRC32/Adler32", "nexus": "osint:checksum", "desc": "CRC32 + Adler32 checksum of input text (offline)", "sats": 200, "egress": False}, {"id": "o_chesscom", "name": "Chess.com", "nexus": "osint:chesscom", "desc": "Public player profile + ratings", "sats": 200, "egress": False}, {"id": "o_cidr", "name": "CIDR Calculator", "nexus": "osint:cidr", "desc": "Subnet calc: network, mask, host range, count (offline)", "sats": 200, "egress": False}, {"id": "o_circlhash", "name": "Hash Lookup", "nexus": "osint:circlhash", "desc": "Known-file lookup (CIRCL hashlookup)", "sats": 200, "egress": False}, {"id": "o_clickjacking", "name": "Clickjacking", "nexus": "osint:clickjacking", "desc": "X-Frame-Options + CSP frame-ancestors check", "sats": 200, "egress": False}, {"id": "o_cloud", "name": "Cloud Provider", "nexus": "osint:cloud", "desc": "AWS/GCP/Azure/etc. detection + hosting flag", "sats": 200, "egress": False}, {"id": "o_codeberg", "name": "Codeberg", "nexus": "osint:codeberg", "desc": "Codeberg/Gitea public user", "sats": 200, "egress": False}, {"id": "o_codeforces", "name": "Codeforces", "nexus": "osint:codeforces", "desc": "Codeforces competitive programmer rating & rank", "sats": 200, "egress": False}, {"id": "o_color", "name": "Color Parser", "nexus": "osint:color", "desc": "hex/rgb -> rgb/hsl + nearest name (offline)", "sats": 200, "egress": False}, {"id": "o_cookies", "name": "Cookie Audit", "nexus": "osint:cookies", "desc": "Secure/HttpOnly/SameSite flag review", "sats": 200, "egress": False}, {"id": "o_cors", "name": "CORS Check", "nexus": "osint:cors", "desc": "Origin-reflection / wildcard misconfig", "sats": 200, "egress": False}, {"id": "o_cratedownloads", "name": "Crate Downloads", "nexus": "osint:cratedownloads", "desc": "Download totals for a Rust crate", "sats": 200, "egress": False}, {"id": "o_crates", "name": "crates.io", "nexus": "osint:crates", "desc": "Rust crate stats + downloads", "sats": 200, "egress": False}, {"id": "o_cratestats", "name": "crates.io Stats", "nexus": "osint:cratestats", "desc": "Rust crate downloads, version, repo (no key)", "sats": 200, "egress": False}, {"id": "o_crc32", "name": "CRC-32 Checksum", "nexus": "osint:crc32", "desc": "Compute CRC-32 of input", "sats": 200, "egress": False}, {"id": "o_credential_stuffing", "name": "Credential Stuffing Risk", "nexus": "osint:credential_stuffing", "desc": "Check breach + stuffing risk", "sats": 200, "egress": False}, {"id": "o_crossrefauthor", "name": "Crossref Author", "nexus": "osint:crossrefauthor", "desc": "Works by author/keyword (Crossref)", "sats": 200, "egress": False}, {"id": "o_crypto", "name": "Crypto Address", "nexus": "osint:crypto", "desc": "BTC/ETH balance & tx history", "sats": 200, "egress": False}, {"id": "o_cryptomarket", "name": "Crypto Market", "nexus": "osint:cryptomarket", "desc": "Global market cap, BTC dominance, 24h volume (CoinGecko)", "sats": 200, "egress": False}, {"id": "o_csp_parse", "name": "CSP Analyzer", "nexus": "osint:csp_parse", "desc": "Content-Security-Policy header analysis & grade", "sats": 200, "egress": False}, {"id": "o_cve", "name": "CVE Lookup", "nexus": "osint:cve", "desc": "CVE detail + CVSS (CIRCL, no key)", "sats": 200, "egress": False}, {"id": "o_cve_poc_checker", "name": "CVE POC Check", "nexus": "osint:cve_poc_checker", "desc": "Check if a CVE has public POC/exploit code", "sats": 200, "egress": False}, {"id": "o_cve_severity", "name": "CVE Severity", "nexus": "osint:cve_severity", "desc": "CVSS + EPSS + KEV for a CVE", "sats": 200, "egress": False}, {"id": "o_cve_timeline", "name": "CVE Timeline", "nexus": "osint:cve_timeline", "desc": "When a CVE was discussed (Twitter/Reddit/News)", "sats": 200, "egress": False}, {"id": "o_cvedetail", "name": "CVE Detail", "nexus": "osint:cvedetail", "desc": "Full CVE record (CVSS, refs) via CIRCL", "sats": 200, "egress": False}, {"id": "o_datacite", "name": "DataCite Search", "nexus": "osint:datacite", "desc": "Research datasets/DOIs by keyword", "sats": 200, "egress": False}, {"id": "o_datauri", "name": "Data URI Parse", "nexus": "osint:datauri", "desc": "Parse or create data: URIs", "sats": 200, "egress": False}, {"id": "o_decode", "name": "Decoder", "nexus": "osint:decode", "desc": "Auto base64/hex/URL-decode + refang", "sats": 200, "egress": False}, {"id": "o_dehashed_domain", "name": "DeHashed Domain", "nexus": "osint:dehashed_domain", "desc": "DeHashed public page scrape for domain breach exposure", "sats": 200, "egress": False}, {"id": "o_depsdev", "name": "deps.dev", "nexus": "osint:depsdev", "desc": "Open-source insights: versions, default", "sats": 200, "egress": False}, {"id": "o_devto", "name": "dev.to", "nexus": "osint:devto", "desc": "Forem/dev.to public profile", "sats": 200, "egress": False}, {"id": "o_dirlisting", "name": "Directory Listing", "nexus": "osint:dirlisting", "desc": "Open directory-index exposure (per-target)", "sats": 200, "egress": False}, {"id": "o_disasters", "name": "Disasters (GDACS)", "nexus": "osint:disasters", "desc": "Active worldwide disasters: quakes/cyclones/floods (feeds globe)", "sats": 200, "egress": False}, {"id": "o_dns", "name": "DNS Records", "nexus": "osint:dns", "desc": "A/AAAA/MX/NS/TXT/CNAME/SOA/CAA records", "sats": 200, "egress": False}, {"id": "o_dnsbl", "name": "DNS Blocklist", "nexus": "osint:dnsbl", "desc": "Spamhaus/Barracuda/SORBS/SpamCop check", "sats": 200, "egress": False}, {"id": "o_dnsgraph", "name": "DNS Graph (HE)", "nexus": "osint:dnsgraph", "desc": "Hurricane Electric DNS delegation info", "sats": 200, "egress": False}, {"id": "o_dnsmx", "name": "MX (DoH)", "nexus": "osint:dnsmx", "desc": "MX records via Google DNS-over-HTTPS", "sats": 200, "egress": False}, {"id": "o_dnsprop", "name": "DNS Propagation", "nexus": "osint:dnsprop", "desc": "Compare A records across Google/Cloudflare/Quad9", "sats": 200, "egress": False}, {"id": "o_dnsquery", "name": "DNS A Record", "nexus": "osint:dnsquery", "desc": "DNS A record lookup via Google DoH", "sats": 200, "egress": False}, {"id": "o_dnsrecon", "name": "DNS Recon", "nexus": "osint:dnsrecon", "desc": "Query ALL DNS record types at once", "sats": 200, "egress": False}, {"id": "o_dnsverify", "name": "TXT Verifications", "nexus": "osint:dnsverify", "desc": "Which SaaS a domain is enrolled in (TXT tokens)", "sats": 200, "egress": False}, {"id": "o_dockerhub", "name": "Docker Hub Repo", "nexus": "osint:dockerhub", "desc": "Docker Hub repo pulls, stars, last update (no key)", "sats": 200, "egress": False}, {"id": "o_doh", "name": "DoH Records", "nexus": "osint:doh", "desc": "Uncommon DNS records (HTTPS/SVCB/TLSA/SRV/NAPTR…)", "sats": 200, "egress": False}, {"id": "o_doi", "name": "DOI Resolver", "nexus": "osint:doi", "desc": "Crossref publication metadata for a DOI", "sats": 200, "egress": False}, {"id": "o_ean", "name": "Barcode/EAN", "nexus": "osint:ean", "desc": "EAN/UPC check digit + GS1 country prefix (offline)", "sats": 200, "egress": False}, {"id": "o_elevation", "name": "Elevation", "nexus": "osint:elevation", "desc": "Ground elevation in metres (Open-Meteo)", "sats": 200, "egress": False}, {"id": "o_email", "name": "Email Intel", "nexus": "osint:email", "desc": "Gravatar, MX, disposable detection", "sats": 200, "egress": False}, {"id": "o_emailrep", "name": "Email Reputation", "nexus": "osint:emailrep", "desc": "emailrep.io: malicious/spam/breach flags for email (no key, limited)", "sats": 200, "egress": False}, {"id": "o_emailsec", "name": "Email Security", "nexus": "osint:emailsec", "desc": "SPF / DMARC / DKIM posture", "sats": 200, "egress": False}, {"id": "o_ens", "name": "ENS Resolve", "nexus": "osint:ens", "desc": "ENS name <-> ETH address + avatar", "sats": 200, "egress": False}, {"id": "o_epoch", "name": "Epoch Time", "nexus": "osint:epoch", "desc": "Unix timestamp <-> UTC datetime", "sats": 200, "egress": False}, {"id": "o_epss", "name": "EPSS Score", "nexus": "osint:epss", "desc": "Exploitation probability (FIRST EPSS)", "sats": 200, "egress": False}, {"id": "o_exploit_cve", "name": "CVE Exploits", "nexus": "osint:exploit_cve", "desc": "Exploit-DB + GitHub POCs for a CVE", "sats": 200, "egress": False}, {"id": "o_favicon", "name": "Favicon Hash", "nexus": "osint:favicon", "desc": "favicon md5/sha256 for pivoting", "sats": 200, "egress": True}, {"id": "o_feeds", "name": "RSS / Atom Feeds", "nexus": "osint:feeds", "desc": "Discover syndication feeds on a site", "sats": 200, "egress": False}, {"id": "o_feodoips", "name": "Feodo C2 List", "nexus": "osint:feodoips", "desc": "Is IP on abuse.ch Feodo botnet C2 list", "sats": 200, "egress": False}, {"id": "o_flightsnear", "name": "Flights Nearby", "nexus": "osint:flightsnear", "desc": "Live aircraft within ~1° of coords (OpenSky)", "sats": 200, "egress": False}, {"id": "o_formaudit", "name": "Form Audit", "nexus": "osint:formaudit", "desc": "Enumerate forms/inputs (login/upload) — attack surface", "sats": 200, "egress": False}, {"id": "o_genderize", "name": "Gender Predictor", "nexus": "osint:genderize", "desc": "Predict gender from a first name (genderize.io)", "sats": 200, "egress": False}, {"id": "o_geocode", "name": "Geocode", "nexus": "osint:geocode", "desc": "Place name → coordinates (OSM Nominatim)", "sats": 200, "egress": False}, {"id": "o_gh_dorking", "name": "GitHub Dork Search", "nexus": "osint:gh_dorking", "desc": "GitHub code search for target string exposure in public repos", "sats": 200, "egress": False}, {"id": "o_gh_secret_scan", "name": "GitHub Secret Scan", "nexus": "osint:gh_secret_scan", "desc": "Scan GitHub user's public repos for leaked secrets/passwords", "sats": 200, "egress": False}, {"id": "o_ghkeysgpg", "name": "GitHub GPG Key", "nexus": "osint:ghkeysgpg", "desc": "Whether a user publishes a GPG key", "sats": 200, "egress": False}, {"id": "o_github_code", "name": "GitHub Code Search", "nexus": "osint:github_code", "desc": "GitHub unauthenticated code search (10 results)", "sats": 200, "egress": False}, {"id": "o_githubsearch", "name": "GitHub Repo Search", "nexus": "osint:githubsearch", "desc": "Search GitHub repos by keyword", "sats": 200, "egress": False}, {"id": "o_gitlab", "name": "GitLab", "nexus": "osint:gitlab", "desc": "Public user profile", "sats": 200, "egress": False}, {"id": "o_gleif_name", "name": "GLEIF Name", "nexus": "osint:gleif_name", "desc": "GLEIF fuzzy legal-entity name → LEI codes", "sats": 200, "egress": False}, {"id": "o_golangpkg", "name": "Go Module", "nexus": "osint:golangpkg", "desc": "Latest version of a Go module", "sats": 200, "egress": False}, {"id": "o_goproxy", "name": "Go Module", "nexus": "osint:goproxy", "desc": "Latest version of a Go module via module proxy (no key)", "sats": 200, "egress": False}, {"id": "o_gravatarfull", "name": "Gravatar Profile", "nexus": "osint:gravatarfull", "desc": "Full public Gravatar profile + linked accounts", "sats": 200, "egress": False}, {"id": "o_greynoise", "name": "GreyNoise", "nexus": "osint:greynoise", "desc": "Is the IP a known internet scanner — benign/malicious", "sats": 200, "egress": False}, {"id": "o_hackernews", "name": "Hacker News", "nexus": "osint:hackernews", "desc": "Profile: karma, age, activity", "sats": 200, "egress": False}, {"id": "o_hashid", "name": "Hash Identifier", "nexus": "osint:hashid", "desc": "Guess hash algorithm from length/charset", "sats": 200, "egress": False}, {"id": "o_hashtext", "name": "Hash Text", "nexus": "osint:hashtext", "desc": "md5/sha1/sha256/sha512 of text (offline)", "sats": 200, "egress": False}, {"id": "o_headers", "name": "HTTP / Security", "nexus": "osint:headers", "desc": "Headers + security-header scorecard", "sats": 200, "egress": True}, {"id": "o_hexdump", "name": "Hexdump", "nexus": "osint:hexdump", "desc": "Offset/hex/ASCII hexdump of input (offline)", "sats": 200, "egress": False}, {"id": "o_hibp", "name": "HIBP Password Check", "nexus": "osint:hibp", "desc": "Check if a password appeared in breaches via HIBP k-anonymity (no key)", "sats": 200, "egress": False}, {"id": "o_hibp_email", "name": "HIBP Email Breaches", "nexus": "osint:hibp_email", "desc": "Email breach exposure via XposedOrNot (HIBP-compatible, no key)", "sats": 200, "egress": False}, {"id": "o_hnsearch", "name": "HN Search", "nexus": "osint:hnsearch", "desc": "Search Hacker News stories/comments", "sats": 200, "egress": False}, {"id": "o_hnuser", "name": "Hacker News User", "nexus": "osint:hnuser", "desc": "HN profile: karma, created, submission count", "sats": 200, "egress": False}, {"id": "o_holidays", "name": "Public Holidays", "nexus": "osint:holidays", "desc": "Country public holidays this year (nager.at)", "sats": 200, "egress": False}, {"id": "o_homoglyph", "name": "Homoglyph", "nexus": "osint:homoglyph", "desc": "Detect confusable/mixed-script spoofing chars (offline)", "sats": 200, "egress": False}, {"id": "o_hostname", "name": "Reverse DNS", "nexus": "osint:hostname", "desc": "IP → hostname via reverse DNS", "sats": 200, "egress": False}, {"id": "o_hstspreload", "name": "HSTS Preload", "nexus": "osint:hstspreload", "desc": "Is the domain on the browser HSTS preload list", "sats": 200, "egress": False}, {"id": "o_htmlcomments", "name": "HTML Comments", "nexus": "osint:htmlcomments", "desc": "Extract HTML comments — leaked TODOs/paths/software", "sats": 200, "egress": False}, {"id": "o_htmlencode", "name": "HTML Encode/Decode", "nexus": "osint:htmlencode", "desc": "HTML entity encode/decode", "sats": 200, "egress": False}, {"id": "o_httpcode", "name": "HTTP Status Code", "nexus": "osint:httpcode", "desc": "HTTP status code meaning & family (offline)", "sats": 200, "egress": False}, {"id": "o_httping", "name": "HTTP Ping", "nexus": "osint:httping", "desc": "Reachability + response timing", "sats": 200, "egress": False}, {"id": "o_httpmethods", "name": "HTTP Methods", "nexus": "osint:httpmethods", "desc": "Allowed methods + TRACE/risky-verb check", "sats": 200, "egress": False}, {"id": "o_hudsonrock", "name": "HudsonRock Stealer", "nexus": "osint:hudsonrock", "desc": "Stealer-log exposure check via HudsonRock Cavalier free API", "sats": 200, "egress": False}, {"id": "o_huggingface", "name": "HuggingFace", "nexus": "osint:huggingface", "desc": "HuggingFace user profile or model card", "sats": 200, "egress": False}, {"id": "o_imagerev", "name": "Reverse Image", "nexus": "osint:imagerev", "desc": "Google Lens / Yandex / Bing / TinEye search links", "sats": 200, "egress": False}, {"id": "o_infra_fingerprint", "name": "Infra Fingerprint", "nexus": "osint:infra_fingerprint", "desc": "Infrastructure fingerprinting + hosting", "sats": 200, "egress": False}, {"id": "o_intelx_email", "name": "XposedOrNot Breach", "nexus": "osint:intelx_email", "desc": "Email breach exposure — breach names, data types, paste hits (XposedOrNot, no key)", "sats": 200, "egress": False}, {"id": "o_internetdb", "name": "Shodan InternetDB", "nexus": "osint:internetdb", "desc": "Open ports, CPEs, tags, known CVEs for a host", "sats": 200, "egress": False}, {"id": "o_ioc_reputation", "name": "IOC Reputation", "nexus": "osint:ioc_reputation", "desc": "Cross-check IP/domain/hash across feeds", "sats": 200, "egress": False}, {"id": "o_ip_math", "name": "IP Math", "nexus": "osint:ip_math", "desc": "CIDR: network/broadcast/range/host count (offline)", "sats": 200, "egress": False}, {"id": "o_ipfull", "name": "IP Full Profile", "nexus": "osint:ipfull", "desc": "Rich geo+ASN+proxy/mobile/hosting flags", "sats": 200, "egress": False}, {"id": "o_ipgeo", "name": "IP Geolocation", "nexus": "osint:ipgeo", "desc": "Geo, ISP, ASN, proxy/hosting flags", "sats": 200, "egress": False}, {"id": "o_ipint", "name": "IP ↔ Integer", "nexus": "osint:ipint", "desc": "IPv4 ↔ integer ↔ hex (offline)", "sats": 200, "egress": False}, {"id": "o_ipv4classify", "name": "IP Classify", "nexus": "osint:ipv4classify", "desc": "Classify IP: private/loopback/multicast/global (offline)", "sats": 200, "egress": False}, {"id": "o_ipwhois", "name": "IP WHOIS / RDAP", "nexus": "osint:ipwhois", "desc": "Network owner, range, abuse contact", "sats": 200, "egress": False}, {"id": "o_isbn", "name": "ISBN Book", "nexus": "osint:isbn", "desc": "Book metadata (OpenLibrary) + checksum", "sats": 200, "egress": False}, {"id": "o_isexitnode", "name": "Tor Exit Check", "nexus": "osint:isexitnode", "desc": "Is this a Tor exit node?", "sats": 200, "egress": False}, {"id": "o_isin", "name": "ISIN Validate", "nexus": "osint:isin", "desc": "Validate ISIN security identifier check digit (offline)", "sats": 200, "egress": False}, {"id": "o_isotime", "name": "Timestamp Convert", "nexus": "osint:isotime", "desc": "Parse/convert a timestamp (offline)", "sats": 200, "egress": False}, {"id": "o_jarm", "name": "JARM / InternetDB", "nexus": "osint:jarm", "desc": "Shodan InternetDB: ports, CPEs, vulns, tags (no key)", "sats": 200, "egress": False}, {"id": "o_jslibs", "name": "JS Libraries", "nexus": "osint:jslibs", "desc": "Enumerate