SkyeGate

If their wallet meets the condition, they see the content. If it doesn't, they don't.

SkyeGate Pro for Vercel

Drop a wallet gate into any Next.js app. Bring your own wallet stack: wagmi, RainbowKit, ConnectKit, Privy, whatever you already use. @skyemeta/skyegate handles the gating layer. Four condition types, 37 blockchains, server-side JWT validation, same SKYE license key as the WordPress plugin.

npm install @skyemeta/skyegate

Powered by The Insumer Model™ condition-based access API.

Five Minutes to a Wallet Gate

Three steps. No configuration. No magic.

1. Install

npm install @skyemeta/skyegate

Peer dep: react ^18 (only if you import the React entry). Runtime dep: jose. Zero wallet libs. You use your own.

2. Set your license key

# .env.local
NEXT_PUBLIC_SKYE_LICENSE_KEY=SKYE-XXXX-XXXX-XXXX

Your SKYE license key is safe to expose. The proxy auto-binds it to your production domain on first use; other apexes are rejected.

3. Drop in <GatedContent />

Wrap whatever you want gated. The component handles the verify call, status transitions, and conditional rendering. Server-side validation goes in a route handler.

app/page.tsx
'use client';
import { useAccount } from 'wagmi';
import { GatedContent } from '@skyemeta/skyegate/react';

export default function Page() {
  const { address } = useAccount();
  return (
    <GatedContent
      address={address}
      conditions={[{ type: 'farcaster_id' }]}
      licenseKey={process.env.NEXT_PUBLIC_SKYE_LICENSE_KEY!}
      loading={<p>Verifying…</p>}
      fallback={<p>Connect a Farcaster-linked wallet.</p>}
      onPass={async (jwt) => {
        const res = await fetch('/api/gated', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ jwt }),
        });
        // render res.json().secret …
      }}
    >
      <p>Welcome, Farcaster user.</p>
    </GatedContent>
  );
}
app/api/gated/route.ts
import { validateContentToken } from '@skyemeta/skyegate';

export const runtime = 'nodejs';

export async function POST(req: Request) {
  const { jwt } = await req.json();
  const result = await validateContentToken(jwt, {
    expectedConditions: [{ type: 'farcaster_id' }],
  });
  if (!result.pass) {
    return Response.json(
      { error: result.error },
      { status: 403 },
    );
  }
  return Response.json({
    secret: 'Real gated content here.',
  });
}

Clone the full starter app →

Four Condition Types

Same vocabulary as the WordPress plugin. Stack up to 10 per gate; pass=true requires all of them to be met.

Token balance

ERC-20, SPL, native ETH/SOL/MATIC, XRPL trust line tokens, plus Bitcoin, Tron, Stellar & Sui. 37 chains.

{
  type: 'token_balance',
  contractAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  chainId: 1,
  threshold: 100,
  decimals: 6,         // USDC
}

NFT ownership

ERC-721, ERC-1155, Solana SPL NFTs. Match by collection contract.

{
  type: 'nft_ownership',
  contractAddress: '0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85',
  chainId: 1,          // ENS .eth
}

EAS attestation

Ethereum Attestation Service templates: Coinbase Verified, Gitcoin Passport, more.

{
  type: 'eas_attestation',
  template: 'coinbase_verified_account',
}

Farcaster identity

Wallet linked to a Farcaster account (FID present). New in Pro 1.4.0.

{
  type: 'farcaster_id',
}

Match the same conditions in validateContentToken's expectedConditions on the server side. That's how a JWT earned for one route can't unlock another.

API at a Glance

verifyConditions(params)

Promise<{ pass, jwt, raw, error? }>

Low-level imperative call. The React hook + component use this internally; reach for it in non-React contexts (server actions, API routes, Node scripts).

Required params: address, conditions[], licenseKey. Optional: walletType ('evm' | 'solana'), endpoint, domain.

validateContentToken(jwt, options?)

Promise<{ valid, pass, payload?, error? }>

Server-side JWT validation. Verifies the ECDSA P-256 signature against InsumerAPI's JWKS, checks issuer + expiry via jose, and (if you pass expectedConditions) confirms the signed conditions match what the route requires.

Trust the math, not a company, including us. Every result is independently verifiable by any third party using the public JWKS.

useSkyeGate(options)

{ status, pass, jwt, error, refetch }

React hook. Same options as verifyConditions, plus enabled to gate the call. status cycles through 'idle' → 'verifying' → 'pass' | 'fail' | 'error'.

<GatedContent />

JSX.Element

Declarative wrapper. Renders children on pass, fallback otherwise, loading while verifying. Optional onPass(jwt) callback fires once when the gate first passes. Use it to fetch gated content from your server.

Full API reference on GitHub →

How It Works

your Next.js app
  ↓ verifyConditions(address, conditions, licenseKey)
  ↓
skyemeta.com/api/verify    ← SkyeMeta proxy validates SKYE key + domain
  ↓
api.insumermodel.com       ← InsumerAPI returns a signed boolean
  ↓                       (no balances exposed)
JWT signed with ECDSA P-256
  ↓ POSTed to your server
  ↓
validateContentToken(jwt)  ← jose + JWKS, signature + issuer + expiry +
  ↓                       condition match
gated content delivered

The wallet's actual balances never reach your server or your customers. Only the signed yes-or-no on whether the condition was met. Trust the math, not a company, including us.

One License, One Site, with Sensible Defaults

Auto-bind on first production use

Your license has no domain at first. The first call from a real apex (e.g. myapp.com) auto-binds the license to that apex. Subsequent calls from myapp.com and any subdomain (staging.myapp.com, preview.myapp.com, app.myapp.com) are accepted.

Calls from a different apex are rejected with License bound to myapp.com.

Dev / preview hosts skip the bind

localhost, 127.0.0.1, *.vercel.app, and *.local verify normally but never bind the license. Vercel preview deploys, local dev, and .local hostnames don't burn your production bind.

Treat your license key as you would any per-domain credential. To move a key to a different production apex, contact support.

WordPress Plugin vs Vercel SDK

WordPress plugin Vercel SDK (this page)
DistributionDirect .zip from skyemeta.comnpm install @skyemeta/skyegate
StackPHP + bundled JSTypeScript / React
Wallet connectBundled, multi-walletBring your own (wagmi, RainbowKit, ConnectKit, Privy)
License keySame SKYE keySame SKYE key
ConditionsAll 4 types, up to 10 stackedAll 4 types, up to 10 stacked
Chains3737
SourceClosed (proprietary plugin)Open (MIT, GitHub)

One Pro license. Pick the channel that matches your stack, or use both, on the same key, no extra cost.

Get a Key

SkyeGate Pro is $49/mo or $350/yr per domain. Same key works on the WordPress plugin and this SDK.

$350/yr, Save 40% or subscribe monthly

Comparison, FAQ, and the WordPress option at skyemeta.com/skyegate.

Same Engine. Different Use Cases.

Ready to gate some content?

Bring your own wallet stack. We bring the gating layer.