Skip to content
View horizon-pulse's full-sized avatar
  • Joined Sep 17, 2026

Block or report horizon-pulse

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
horizon-pulse/README.md

Horizon Pulse

Pay-per-call crypto market pulse, signals, funding, yield rankings, portfolio risk, gas, plus public URL fetch → clean text, universal http proxy, and extract → structured fields for AI agents, monetized with the x402 protocol on Base mainnet and Solana mainnet (USDC, exact, same price on both).

This repo is a Next.js App Router service ready to deploy (e.g. Vercel) and push to:

https://github.com/horizon-pulse/horizon-pulse.git

Public host

Role URL
Canonical https://horizonpulse.dev
Backup (Vercel) https://horizon-pulse-seven.vercel.app

Prefer horizonpulse.dev in agent docs, OpenAPI, and clients. The *.vercel.app URL remains a working fallback.

What it is

  • Agents hit fourteen live paid HTTP endpoints (six crypto frozen; /api/fetch + /api/http + /api/extract + /api/x402-check + /api/bazaar-check + /api/screenshot + /api/search + /api/pdf non-crypto LIVE — see below).
  • Unpaid requests receive HTTP 402 with x402 v2 requirements: canonical wire is the PAYMENT-REQUIRED header, with one accepts entry per network: Base (CAIP-2 eip155:8453, Base USDC, the treasury below) and Solana (CAIP-2 solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp, USDC mint, the Solana payTo below). See docs/solana-rail.md.
  • Retry with an x402 v2 PAYMENT-SIGNATURE header. The facilitator (Coinbase CDP on Base, PayAI on Solana) verifies + settles, then the route returns live data.
  • No stubbed prices or fake APYs: Coinbase Exchange (CoinGecko fallback) for spot; CoinGecko OHLC (Coinbase candles fallback) for signals; OKX for perpetual funding (Binance/Bybit are often geo-blocked on Vercel); DefiLlama for yield pools; public RPC balanceOf for portfolio (real balances only); eth_feeHistory / eth_gasPrice for gas (real fees only); /api/fetch returns best-effort cleaned text from a requested public URL (SSRF-safe, size/time capped); /api/http is a raw universal proxy (filtered headers, text|base64 body, SSRF-safe) priced $0.01 for volume; /api/extract returns best-effort structured page fields from a URL or HTML (SSRF-safe, size/time capped) priced $0.015.
  • Never invent metrics; never advertise routes that 404; never cite a cached balance — /status reads live USDC balanceOf on payTo. Honest: current payTo is interim Coinbase-custodial (not Safe/multisig).

Catalog status (post first settlement)

Fact Value
Live paid routes 14 (table below) — six crypto + /api/fetch + /api/http + /api/extract + /api/x402-check + /api/bazaar-check + /api/screenshot + /api/search + /api/pdf
First settle /api/pulse $0.005 — tx 0xedbd1a51…
Crypto policy Frozen — six crypto routes: no price changes
Fetch Non-crypto LIVE: clean-text ($0.02)
Http Non-crypto LIVE: universal proxy ($0.01 volume price)
Extract Non-crypto LIVE: structured HTML ($0.015)

Coming-soon / placeholder / 404 routes are not listed on /, /status, or this README.

Agent how-to (x402 v2)

  1. GET a paid route with no payment → HTTP 402.
  2. Read PAYMENT-REQUIRED (v2) and pick one accepts entry. Confirm network (eip155:8453 for Base or solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp for Solana), USDC on that network, exact atomic amount, and that network's payTo.
  3. Sign and retry the same GET with PAYMENT-SIGNATURE (v2 primary; do not rely on legacy X-PAYMENT as the settle path).
  4. On success: the facilitator settles on the network you paid on; response body is the live JSON for that route.

Optional: OPTIONS on a paid route returns discovery + the same PAYMENT-REQUIRED challenge without charging.

Agent integration

  • Skill file: /skill.md, plain markdown an agent can follow end to end (generated from public/openapi.json by lib/agent-skill.ts).
  • Guide: /agents: pay flow, skill and MCP setup.
  • Local MCP server: mcp/, stdio, every live route as a tool, pays the x402 challenge from a buyer wallet you configure, with per-call and per-session caps (quote-only without a key). Not published to npm; install from this repo.
  • Hosted MCP: POST https://horizonpulse.dev/mcp (streamable HTTP) for MCP clients that can pay x402 themselves.

Treasury (payTo)

Field Value
payTo 0x5b32c973596078a967562ca652761404f19be0e9
Basename horizonpulsebase.base.eth (resolves to the payTo above; a label only, the 402 carries the hex address)
Custody Interim Coinbase-custodial Base address (Michael-controlled). Not a Safe or multisig.
Upgrade path Move later to a non-custodial Safe / multisig when ready — same catalog and prices.
USDC (Base) 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Network base (CAIP-2 eip155:8453)
Facilitator https://api.cdp.coinbase.com/platform/v2/x402
Solana payTo BjY98A6dS3GGLZdz2zHy8wK7XAwnQgNhCc66mfmBTRPz (operator-controlled; pinned in lib/solana-config.ts; payments credit its USDC token account)
USDC (Solana) EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
Solana network CAIP-2 solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp (exact only)
Solana facilitator PayAI https://facilitator.payai.network

Do not use the retired address 0xe16A1b12404cB2EbC6e783beCA6E2A9253c3dC7E.

PAY_TO may be overridden via env, but defaults to the address above. Agents should treat current payTo as the live settlement destination; custody shape may change later without changing route prices.

Endpoints

Paid (14 — six crypto frozen + fetch + http + extract + x402-check + bazaar-check + screenshot + search + pdf):

Route Price Auth
GET /api/pulse $0.005 USDC (5000 atomic) x402 v2
GET /api/signals $0.015 USDC (15000 atomic) x402 v2
GET /api/yield $0.02 USDC (20000 atomic) x402 v2
GET /api/portfolio?address=0x… $0.04 USDC (40000 atomic) x402 v2
GET /api/gas $0.01 USDC (10000 atomic) x402 v2
GET /api/funding $0.01 USDC (10000 atomic) x402 v2
GET /api/fetch?url=https://… $0.02 USDC (20000 atomic) x402 v2
GET / POST /api/http $0.01 USDC (10000 atomic) x402 v2
GET / POST /api/extract $0.015 USDC (15000 atomic) x402 v2
GET /api/x402-check?url=https://… $0.01 USDC (10000 atomic) x402 v2
GET /api/bazaar-check?url=… $0.01 USDC (10000 atomic) x402 v2
GET /api/screenshot?url=https://… $0.02 USDC (20000 atomic) x402 v2
GET /api/search?q=…&n=3 $0.03 USDC (30000 atomic) x402 v2
GET /api/pdf?url=https://… $0.02 USDC (20000 atomic) x402 v2

Free (not paid APIs):

Route Auth
GET /status public HTML — live USDC balanceOf on payTo (honest RPC error if fetch fails)
GET / landing — live paid catalog + agent how-to

GET /api/pulse

Real spot prices for BTC / ETH / SOL (Coinbase Exchange, CoinGecko fallback) with per-asset momentum, plus overall momentum / sentiment / direction (up/down/flat, a neutral description of the average 24h move; renamed from signal, see CHANGELOG.md).

  • runtime = 'nodejs'
  • Discovery: Bazaar extension + outputSchema.input.discoverable: true in payment requirements

GET /api/signals

RSI(14), MACD(12,26,9), Bollinger bands from CoinGecko OHLC closes, plus OKX funding rates. Includes a methodology field.

  • runtime = 'nodejs'
  • Discoverable for agents

GET /api/yield

Ranked DeFi yield pools from the public DefiLlama yields API (https://yields.llama.fi/pools).

  • Hard filter: TVL ≥ $10M; exclude non-finite APY and DefiLlama outlier pools
  • Preference: keep stablecoin and/or single-asset (exposure === "single") pools
  • Transparent ranking: preferenceTier DESC (2 = stablecoin+single, 1 = either), then APY DESC, then TVL DESC
  • Every response includes a methodology object (also on error bodies)
  • Price: $0.02 USDC (20000 atomic)
  • runtime = 'nodejs', dynamic = 'force-dynamic'
  • Unpaid GET → 402 + PAYMENT-REQUIRED (v2, eip155:8453) · payTo 0x5b32c973596078a967562ca652761404f19be0e9

GET /api/portfolio

On-chain portfolio snapshot for one EVM address (?address=0x…, required).

  • Networks: Base + Ethereum mainnet (public RPCs; optional BASE_RPC_URL / ETH_RPC_URL with failover)
  • Tokens: native ETH; USDC, WETH, DAI on both chains; WBTC on Ethereum; cbBTC on Base (honest substitute — Base has no BitGo WBTC)
  • USD marks via Coinbase public exchange rates (CoinGecko for the rest or on Coinbase failure); real balances only — if an RPC fails, that network is marked failed in networks[] / warnings
  • Rule-based risk score (0–100) and rule findings (largest asset weight vs 35%/50%, stablecoin share vs 15%/85%, largest chain share vs 85%, low native ETH gas balance; returned in the suggestions array as plain findings, no instructions) with transparent formulas in methodology
  • Price: $0.04 USDC (40000 atomic)
  • runtime = 'nodejs', dynamic = 'force-dynamic'
  • Unpaid GET → 402 + PAYMENT-REQUIRED (v2, eip155:8453) · payTo 0x5b32c973596078a967562ca652761404f19be0e9

GET /api/gas

Live gas snapshot for Base and Ethereum from public RPCs.

  • Prefers eth_feeHistory (last 20 blocks, reward percentiles 10/50/90): baseFeeGwei, priorityFeeGwei (p50), suggestedMaxFeeGwei (= 2×baseFee + priority)
  • Falls back to eth_gasPrice when feeHistory is unavailable
  • Transparent timingHint: cheap / normal / expensive from percentile rank of the latest confirmed baseFee within the feeHistory window (<33 / 33–67 / >67); documented in methodology — not a forecast
  • Optional ETH USD (Coinbase Exchange, CoinGecko fallback) for a simple 21k-gas transfer cost estimate (simpleTransfer.costUsd)
  • Price: $0.01 USDC (10000 atomic)
  • runtime = 'nodejs', dynamic = 'force-dynamic'
  • Unpaid GET → 402 + PAYMENT-REQUIRED (v2, eip155:8453) · payTo 0x5b32c973596078a967562ca652761404f19be0e9

GET /api/funding

Live perpetual funding rates for BTC / ETH / SOL from OKX (same source as /api/signals; Vercel-friendly — not Binance/Bybit).

  • Reuses lib/okx.ts (fetchAllFunding)
  • Transparent methodology on every response (including errors)
  • Optional crowding hint from funding sign + magnitude only (rules: quiet / mild / elevated / extreme; side longs/shorts/neutral) — not a forecast
  • Honesty: real OKX data only
  • Price: $0.01 USDC (10000 atomic) — cheap poll product for agents
  • runtime = 'nodejs', dynamic = 'force-dynamic'
  • Unpaid GET → 402 + PAYMENT-REQUIRED (v2, eip155:8453) · payTo 0x5b32c973596078a967562ca652761404f19be0e9

GET /api/fetch

Fetch a public http(s) URL (?url=https://…, required) and return best-effort clean text/markdown.

  • SSRF-safe: blocks localhost, private, link-local, and metadata IPs; re-checks each redirect hop
  • Caps: ~200KB raw body, 8s timeout, max 3 redirects
  • Preferred Content-Types: text/html, text/plain, application/json, text/markdown
  • Cleaning is best-effort (strip script/style/chrome, collapse whitespace) — not a full readability engine
  • Price: $0.02 USDC (20000 atomic)
  • runtime = 'nodejs', dynamic = 'force-dynamic'
  • Unpaid GET → 402 + PAYMENT-REQUIRED (v2, eip155:8453) · payTo 0x5b32c973596078a967562ca652761404f19be0e9

GET / POST /api/http

Universal agent HTTP proxy — call a public http(s) URL with optional method / headers / body; get back upstream status, filtered headers, and body (text or base64) plus contentType and elapsedMs.

  • Price choice: $0.01 USDC (10000 atomic) for volume. /api/fetch stays $0.02 (specialized clean-text). Prefer /api/http for raw proxy traffic.
  • Inputs: url (required); method (GET default; GET|POST|HEAD|PUT|PATCH|DELETE); optional allowlisted headers (no Cookie / hop-by-hop); optional body for POST/PUT/PATCH (size-capped)
  • GET query: ?url=&method=&headers=<json>; POST JSON body for full control including upstream body
  • SSRF-safe (shared guards with /api/fetch): blocks private/link-local/metadata; http/https only; re-checks redirects
  • Caps: ~384KB response body, 64KB request body, 12s timeout, max 3 redirects
  • Honesty: upstream 4xx/5xx returned in status when the hop succeeded; proxy failures use honest error codes
  • runtime = 'nodejs', dynamic = 'force-dynamic'
  • Unpaid GET/POST → 402 + PAYMENT-REQUIRED (v2, eip155:8453) · payTo 0x5b32c973596078a967562ca652761404f19be0e9
  • Bazaar discovery advertises GET; POST is paid identically

GET / POST /api/extract

URL or HTML → structured page fields for agents (title, description, canonical, language, links, images, headings, json-ld, text sample).

  • Price choice: $0.015 USDC (15000 atomic) — between /api/http ($0.01) and /api/fetch ($0.02). Same payTo + Base USDC stack.
  • Inputs: url (optional if html provided) and/or html (size-capped). Prefer fetching url with the same SSRF-safe assertSafePublicUrl as fetch/http.
  • GET query: ?url=&fields=<url-encoded json>; POST JSON { url?, html?, fields? } for html payloads
  • Optional fields: up to 20 named CSS selectors, e.g. {"title":"h1","links":{"selector":"a.story","attr":"href","all":true,"limit":5}}. attr is text (default), html, or any attribute (href/src resolved to absolute URLs). Unmatched fields return null plus fieldErrors[name] (no_match, bad_selector, attr_missing, time_budget, document_too_deep, eval_failed). If none match: 422 no_fields_matched, not charged. Hard 2s selector budget; :has() at most once per selector; pages nested >256 levels are refused for fields. Deterministic selectors, no AI.
  • Lightweight regex parse (no cheerio). Empty fields omitted. Not a full browser DOM.
  • Caps: ~200KB HTML, 8s timeout, max 3 redirects (same band as /api/fetch)
  • No cookie jar. Private/localhost/link-local/metadata blocked.
  • runtime = 'nodejs', dynamic = 'force-dynamic'
  • Unpaid GET/POST → 402 + PAYMENT-REQUIRED (v2, eip155:8453) · payTo 0x5b32c973596078a967562ca652761404f19be0e9
  • Bazaar discovery advertises GET; POST is paid identically

GET /status

Public page showing the live USDC balance of the payTo address on Base (via public RPC / BASE_RPC_URL balanceOf) plus the live paid catalog and agent how-to.

  • On RPC failure the page shows an honest error — it does not fall back to a cached balance. Custody note: interim Coinbase-custodial payTo (not Safe/multisig); upgrade path later.
  • First settle noted as /api/pulse $0.005 (0xedbd1a51…); six crypto routes frozen; /api/fetch + /api/http + /api/extract deliberately LIVE.

Local development

Requires Node.js 20+ (tested on 20.19).

cd horizon-pulse
cp .env.example .env.local
# fill CDP_API_KEY_ID + CDP_API_KEY_SECRET for verify/settle
npm install
npm run dev
npm run build && npm start

Environment variables (Vercel / production)

Copy from .env.example:

Variable Required Notes
X402_NETWORK recommended base
PAY_TO optional defaults to 0x5b32c973596078a967562ca652761404f19be0e9
CDP_API_KEY_ID for settle Coinbase Developer Platform
CDP_API_KEY_SECRET for settle PKCS8 PEM (store safely; never commit)
BASE_RPC_URL optional overrides default Base RPC for /status + /api/portfolio + /api/gas
ETH_RPC_URL optional overrides default Ethereum RPC for /api/portfolio + /api/gas

Without CDP keys:

  • Unpaid GET and OPTIONS still return correct 402 / discovery with v2 PAYMENT-REQUIRED (payTo, eip155:8453, USDC amount) — no CDP required for discovery.
  • Requests that include PAYMENT-SIGNATURE (or legacy X-PAYMENT) receive 503 until CDP_API_KEY_ID + CDP_API_KEY_SECRET are set on Vercel (settlement path).
  • Do not expect live GET to 500 when CDP is missing; that was a prior bug fixed by gating withX402 behind payment + CDP credentials.

Stack

  • Next.js 16 (App Router) + TypeScript
  • @x402/next + @x402/core + @x402/evm + @x402/extensions
  • @coinbase/x402 for CDP facilitator auth headers
  • viem for treasury USDC balanceOf on Base, portfolio balances, and gas feeHistory on Base + Ethereum

Deploy notes

  1. Create the GitHub repo / remote https://github.com/horizon-pulse/horizon-pulse.git.
  2. Set Vercel env vars (above). Prefer PEM secret as a single line with \n escapes if the UI is single-line.
  3. Deploy from main. Ensure functions use Node.js runtime (routes already set export const runtime = 'nodejs').
  4. Smoke-test: curl -i https://horizonpulse.dev/api/pulse (or /api/yield, /api/portfolio, /api/gas, /api/funding, /api/fetch?url=https://example.com, /api/http?url=https://example.com, /api/extract?url=https://example.com) should return 402 with payment requirements pointing at the new payTo.
  5. Confirm /status shows the treasury balance for 0x5b32…e0e9.

Push (from this workspace)

This scaffold does not push for you (no credentials). From a machine with GitHub auth:

cd /workspace/horizon-pulse
git init
git add .
git commit -m "feat: Horizon Pulse x402 API with new Base treasury"
git branch -M main
git remote add origin https://github.com/horizon-pulse/horizon-pulse.git
git push -u origin main

If the remote already has history:

git remote add origin https://github.com/horizon-pulse/horizon-pulse.git
git fetch origin
git pull origin main --rebase   # or merge, as appropriate
git push -u origin main

Reference agent (examples/)

Unpaid 402 discovery for the live paid routes listed in the script, plus optional paid single-route when SMOKE_PRIVATE_KEY is set:

cd horizon-pulse
node examples/reference-agent.mjs
# optional paid:
SMOKE_PRIVATE_KEY=0x... SMOKE_ROUTE=/api/pulse node examples/reference-agent.mjs

See examples/README.md. Uses @x402/core + @x402/evm from this package. Never commit secrets.

Paid smoke test (/api/pulse)

End-to-end check against production (or SMOKE_BASE_URL): unpaid 402 → sign EIP-3009 / x402 with a local key → paid 200 + on-chain USDC toward payTo.

cd horizon-pulse
npm install   # if needed; uses existing @x402/* + viem
SMOKE_PRIVATE_KEY=0x... node scripts/smoke-pulse.mjs
# or: npm run smoke:pulse

Optional:

SMOKE_BASE_URL=https://horizonpulse.dev
# backup: https://horizon-pulse-seven.vercel.app
BASE_RPC_URL=https://mainnet.base.org

Never paste your private key in chat, commits, or screenshots. Export it only in your local shell (e.g. Mac mini). Without SMOKE_PRIVATE_KEY, the script exits with usage help (safe dry-run).

License

Private / as designated by the horizon-pulse org.

Popular repositories Loading

  1. horizon-pulse horizon-pulse Public

    TypeScript

  2. awesome-x402 awesome-x402 Public

    Forked from xpaysh/awesome-x402

    🚀 Curated list of x402 resources: HTTP 402 Payment Required protocol for blockchain payments, crypto micropayments, AI agents, API monetization. Includes SDKs (TypeScript, Python, Rust), examples, …

  3. x402-dev x402-dev Public

    Forked from michielpost/x402-dev

    List of x402 facilitators and awesome projects

    C#

  4. gold-402 gold-402 Public

    Forked from Haustorium12/gold-402

    The gold standard for x402 resources. 459 curated entries, every one checked by hand.

    Python

  5. awesome-mcp-servers awesome-mcp-servers Public

    Forked from punkpeye/awesome-mcp-servers

    A collection of MCP servers.

  6. pay-skills pay-skills Public

    Forked from solana-foundation/pay-skills