npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@solinkify/gate-sdk

v0.1.1

Published

AI agent SDK — auto-pay HTTP 402 paywalls and access Solinkify Gate protected content on Solana.

Readme

@solinkify/gate-sdk

Ethical AI agent SDK — access creator-gated content by paying automatically on Solana.

@solinkify/gate-sdk is the client counterpart to @solinkify/gate. When an AI agent hits a 402 Payment Required wall, this SDK handles the entire payment flow automatically: parse the manifest, lock SOL into an on-chain Escrow PDA, retry the request with payment proof, receive the content, then release the payment to the creator.

No manual steps. No custodial wallets. Fully on-chain.


How It Works

Agent calls fetchProtected(url)
        │
        ▼
  GET url → 402 Payment Required + PaymentManifest
        │
        ▼
  Parse manifest (price, escrow_address, endpoint_id)
        │
        ▼
  Price ≤ maxPricePerRequest?  ──No──▶  throw Error (spending cap)
        │ Yes
        ▼
  lock_payment() on-chain
  SOL → Escrow PDA (Solana smart contract)
        │
        ▼
  Retry GET url
  headers: X-Solinkify-Payment + X-Solinkify-Payer
        │
        ▼
  200 OK → Content received
        │
        ▼
  Agent calls release_payment() on-chain
        │
   ┌────┴──────────────┬──────────────────┐
   ▼                   ▼                  ▼
99% → Creator   0.75% → Operator   0.25% → Admin
        │
        ▼
  Escrow PDA closed → rent refunded → Agent

Quick Start

1. Install

npm install @solinkify/gate-sdk @solana/web3.js

2. Load your agent keypair and fetch

import { GateClient } from '@solinkify/gate-sdk';
import { Keypair } from '@solana/web3.js';
import fs from 'fs';

// Load agent keypair (CLI wallet or managed key)
const secret = JSON.parse(fs.readFileSync('/path/to/keypair.json', 'utf-8'));
const agentKeypair = Keypair.fromSecretKey(Uint8Array.from(secret));

const client = new GateClient({
  wallet: agentKeypair,
  rpcUrl: 'https://api.devnet.solana.com',
  maxPricePerRequest: 0.01,   // Will refuse to pay more than this (SOL)
});

const { response, paymentId, escrowPDA } = await client.fetchProtected(
  'https://your-site.com/articles/ai-research'
);

const content = await response.json();
console.log(content);

3. Expected output

→ Requesting content...
← HTTP 402 received. Price: 0.001 SOL
→ Paying 0.001 SOL to escrow...
← Payment confirmed (signature: 3xKp1a...)
→ Retrying with payment proof...
← Content received! (11740 bytes)

API Reference

new GateClient(config)

| Option | Type | Default | Description | |---|---|---|---| | wallet | Keypair | required | Agent's Solana keypair. Used to sign lock_payment and release_payment transactions. | | rpcUrl | string | required | Solana RPC endpoint (e.g. https://api.devnet.solana.com). | | maxPricePerRequest | number | 0.01 | Maximum SOL the agent is willing to pay per request. Requests priced above this throw an error without touching the chain. Can also be set via GATE_MAX_SPEND_SOL env var. | | retries | number | 1 | Number of retry attempts for lock_payment if the transaction fails (max 3). Uses exponential backoff. | | apiUrl | string | 'https://api.solinkify.com' | Solinkify backend URL. Use the default unless self-hosting. |

Environment variables (optional overrides):

| Variable | Description | |---|---| | GATE_MAX_SPEND_SOL | Fallback spending cap if maxPricePerRequest is not set in config. | | GATE_RPC_URL | Fallback RPC URL if rpcUrl is not set in config. |


client.fetchProtected(url, options?)

Fetches a URL with automatic payment handling.

const result = await client.fetchProtected(url, fetchOptions?);

Parameters:

| Parameter | Type | Description | |---|---|---| | url | string | URL to fetch. Must be protected by @solinkify/gate. | | options | RequestInit | Optional standard fetch options (headers, method, body, etc.). |

Returns: Promise<FetchProtectedResult>

interface FetchProtectedResult {
  response: Response;     // The final HTTP response (content)
  paymentId?: string;     // UUID of the payment (present if payment was made)
  escrowPDA?: string;     // Base58 address of the Escrow PDA (present if payment was made)
}

Behavior:

  • If the URL returns 200 directly (not gated), returns immediately — no payment made.
  • If the URL returns 402 without X-Solinkify-Gate header (not a Solinkify gate), returns the 402 response as-is — no payment made.
  • If the URL returns 402 with X-Solinkify-Gate header, triggers the full payment flow.
  • If price exceeds maxPricePerRequest, throws immediately without touching the chain.

Payment Flow Details

Step 1 — Parse the 402 manifest

parser.ts validates the 402 response from @solinkify/gate:

// Checks for X-Solinkify-Gate header to confirm this is a Solinkify gate
isGateway402(response)  // → boolean

// Parses and validates the JSON payment manifest
parse402(response)      // → Promise<PaymentManifest>

A valid manifest looks like:

{
  "error": "Payment Required",
  "message": "Content protected by Solinkify Gate",
  "price": 0.001,
  "currency": "SOL",
  "payment": {
    "escrow_address": "YOUR_CREATOR_WALLET_ADDRESS",
    "payment_id": "",
    "endpoint_id": "techpulsedaily",
    "expires_at": 1715000000
  },
  "info": {
    "sdk": "https://npm.im/@solinkify/gate-sdk",
    "docs": "https://solinkify.io/gate"
  }
}

Note on escrow_address: Despite the name, this field contains the creator's wallet address — not an Escrow PDA address. The SDK reads it as creatorPubkey and uses it to derive the actual Escrow PDA via ["gate_endpoint", creator_pubkey, endpoint_id] and ["gate_escrow", agent_pubkey, payment_id]. Funds flow through the PDA and are released to this creator wallet upon release_payment().

Note on endpoint_id: This is the unique identifier the creator registered when setting up their gate on the Solinkify Gate dashboard. It is stored on-chain as part of the endpoint_config PDA and is used by the SDK to derive the correct PDA for payment. The creator sets this once during registration — the SDK receives it automatically from the 402 manifest. Must be unique within the creator's account, but does not need to be globally unique across all creators.

Step 2 — Lock payment on-chain (payer.ts)

buildAndSubmitPayment() constructs and submits the lock_payment Anchor instruction:

  1. Generates a unique payment_id (UUID v4, dashes stripped → 32 hex chars, fits Solana PDA seed limit)
  2. Derives the endpoint_config PDA from [gate_endpoint, creator_pubkey, endpoint_id]
  3. Derives the escrow PDA from [gate_escrow, agent_pubkey, payment_id]
  4. Builds and signs the lock_payment transaction
  5. Submits and confirms on-chain

PDA seeds:

endpoint_config PDA: ["gate_endpoint", creator_wallet, endpoint_id]
escrow PDA:          ["gate_escrow",   agent_wallet,   payment_id]

Program ID (Devnet): 2q2KWtZbKakmsuoGNVtc9fkPvcs5xdmtVzPHb5zUXXt8

Step 3 — Retry with payment proof

After lock_payment confirms, the SDK retries the original request with two headers:

X-Solinkify-Payment: <payment_id>    // UUID (32 hex chars)
X-Solinkify-Payer:   <agent_pubkey>  // Base58 agent wallet address

@solinkify/gate middleware verifies these headers against the on-chain escrow state before serving content.

Step 4 — Release payment

After content is received, the agent calls release_payment() on-chain. The smart contract enforces the fee split:

Escrow amount  →  99%    Creator wallet
               →  0.75%  Operator treasury
               →  0.25%  Admin treasury
Escrow PDA closed → rent refunded → Agent

Timeout path: If the agent fails to call release_payment(), anyone can trigger it after 3600 seconds. The same fee split applies. This ensures creators are never locked out of their funds.


Spending Cap Safety

The SDK enforces a spending cap at two levels:

// 1. Config-level cap (applies to all requests in this client instance)
const client = new GateClient({
  wallet: agentKeypair,
  rpcUrl: '...',
  maxPricePerRequest: 0.005,
});

// 2. Per-call override (cannot exceed the config-level cap)
// Not supported at fetchProtected() level — set maxPricePerRequest at init.

If the manifest price exceeds the cap, the SDK throws before any on-chain transaction:

Error: Price 0.01 SOL exceeds spending cap 0.005 SOL

You can also set the cap via environment variable:

GATE_MAX_SPEND_SOL=0.005 node agent.js

Error Reference

| Error message | Cause | Action | |---|---|---| | config.wallet is required | No keypair passed to constructor | Pass a valid Keypair | | config.rpcUrl is required | No RPC URL passed | Pass a valid Solana RPC URL | | Price X SOL exceeds spending cap Y SOL | Manifest price > maxPricePerRequest | Raise the cap or skip this URL | | endpoint_id missing from 402 manifest | Creator's @solinkify/gate is outdated | Creator needs to add endpointId to their config | | Solana RPC error: ... | RPC connection failed | Check rpcUrl, try a different endpoint | | lock_payment failed: ... | On-chain transaction rejected | Check agent wallet balance | | Transaction not confirmed: ... | Transaction timed out | Usually transient — retry | | Payment submitted but access denied | Payment verified but middleware rejected | Check payment_id format or contact creator | | Invalid payment manifest from server | Server returned malformed 402 body | Site may not be using @solinkify/gate |


Requirements

  • Node.js 18+
  • A funded Solana keypair (agent wallet)
  • @solana/web3.js v1

Related


Known Limitations

These are current MVP limitations planned for post-hackathon:

  • Devnet only — The smart contract is currently deployed on Solana Devnet. Mainnet deployment is planned post-audit.
  • @solana/web3.js v1 only — The SDK depends on @solana/web3.js v1. v2 has breaking API changes and is not currently supported.
  • Single request at a timefetchProtected() does not support concurrent requests to the same gated URL. Call sequentially or use separate GateClient instances.

License

MIT — see LICENSE


Part of the Solinkify ecosystem.