neonjelly

Start

Auth and keys

No users. Token is the identity. Trial from /start. Paid nj_ keys minted at /admin.

Who can create a key

There is no user table. The token is the identity. Stripe Checkout upgrades the same trial key (billingStatus: stripe) or mints a new paid key.

WhoHow
Anyone/start or POST /v1/trial. One trial per device + AI client. Live reuse also matches the caller IP.
Customer/pricing → Stripe Checkout → /dash. Same key if a trial is in the browser.
Ops/admin with ADMIN_TOKEN.

What a key looks like

  • nj_ — hashed secret, shown once at mint
  • njc_ — connect token on that key. URL: https://mcp.neonjelly.io/c/<njc_>/mcp

Treat both as secrets. Do not put them in a query string.

Clients that can send headers:

  • Authorization: Bearer nj_… or njc_…
  • X-Api-Key: nj_…

Prefer the connect URL. nj_ is shown once on first mint from that IP.

Ask the agent “what's my quota?” — MCP whoami returns plan, usedToday, remainingToday, rate limit, and expiry. Same facts as GET /v1/whoami. Neither call counts against daily quota. When the trial ends or the daily cap hits 0, the agent should call upgrade and open the checkout URL for the user.

Trial rules (code)

  • Plan id trial, billingStatus: trial
  • 100 calls / UTC day, 20 / minute
  • Expires in 14 days
  • Bound to a browser install id (installId) and the AI client (Cursor, Claude, VS Code, …)
  • Live reuse: same install id, or same public IP, returns the same connect URL (no new secret)
  • After expiry, the same device + client gets 403 trial_used — purchase on /pricing. Cursor / Claude do not send a hardware id; the lock is the site cookie/localStorage plus the client name recorded on MCP initialize

Abuse caps on POST /v1/trial

  • One live trial per IP (reuse, do not remint)
  • One trial per install id — expired unpaid trial on that device cannot remint
  • Site requests must send installId (16–80 chars). Cookie nj_install + localStorage nj_install_v1
  • Body may include client: cursor | claude | vscode | chatgpt | windsurf | web
  • 8 mint attempts / 10 min per IP from the site; 3 / 10 min from no-Origin clients (curl)
  • 200 mint attempts / hour globally
  • User-Agent shorter than 8 chars → 403
  • Origin present but not on the allow list → 403
  • Honeypot body field website filled → 204, no key

Daily quota + expiry still apply after mint. A new browser profile (cleared cookies + storage) on a new IP can still mint — Cursor does not expose a machine fingerprint. The global mint cap and 100/day limit the blast radius.

Paid rules (code)

Plan ids: explorer (2,000/day, 30/min), operator (15,000/day, 90/min), scale (50,000/day, 180/min). Stored in keys.json on the MCP host. Ops can revoke or change quotas via PATCH /admin/keys/:id. Stripe Checkout on /pricing sets billingStatus: stripe on the existing trial token, or mints a paid key. Promo codes are Stripe Checkout only — not MCP metadata.

AppSumo lifetime codes redeem at /redeem: 1 code → Explorer, 2 → Operator, 3 → Scale, same quotas, billingStatus: appsumo, no expiry. Codes are validated by POST /v1/appsumo/redeem on the MCP host; stacking later codes needs the existing key.