Installation

npm install @hoodlayerorg/sdk

HoodLayerProvider

import { HoodLayerProvider } from "@hoodlayerorg/sdk";

const hoodlayer = new HoodLayerProvider(config: HoodLayerProviderConfig);

HoodLayerProviderConfig

Option Type Required Description
wallet Signer Yes The provider’s wallet: a viem account, ethers wallet, or compatible signer
apiKey string Yes API key issued in the HoodLayer Dashboard
network "mainnet" \| "testnet" Yes Which Robinhood Chain network to target
rpcUrl string No A custom RPC endpoint for Robinhood Chain
facilitatorUrl string No Override for the Facilitator URL
webhookSecret string No Secret used to check incoming webhook signatures

Methods

hoodlayer.createPlan()

Writes a plan record to the HoodLayer Plan Registry. Once created, it can’t be changed.

const plan = await hoodlayer.createPlan(options: CreatePlanOptions): Promise<Plan>

CreatePlanOptions

Option Type Required Description
name string Yes Name shown for the plan
amount number Yes What each billing cycle costs, in token base units
interval BillingInterval Yes "MONTHLY" \| "WEEKLY" \| "DAILY" \| "PER_REQUEST"
token string No Token address to bill in (default: USDC)
trialPeriodDays number No How many days the free trial lasts
meteredOverage MeteredOverage No Config for usage-based overage billing
const plan = await hoodlayer.createPlan({
  name: "API Pro",
  amount: 49_000_000,   // 49 USDC
  interval: "MONTHLY",
  trialPeriodDays: 7,
  meteredOverage: {
    unit: "1000 tokens",
    price: 2_000, // 0.002 USDC per 1k tokens
  },
});

console.log(plan.id); // save it, this is your plan id

hoodlayer.deprecatePlan()

Flags a plan as deprecated, which blocks new subscriptions. Anyone already subscribed keeps going.

await hoodlayer.deprecatePlan(options: { planId: string }): Promise<void>

hoodlayer.paymentGate()

Middleware for Express/Node.js that puts routes behind a paywall. Unauthenticated requests get a 402 response back; requests carrying a valid payment proof or an active subscription go through.

app.use("/api/v1", hoodlayer.paymentGate(options: PaymentGateOptions))

PaymentGateOptions

Option Type Required Description
pricing PricingRule[] Yes The payment options you want to offer
onSuccess function No Runs after verification succeeds. Called with (req, paymentInfo).
onFailure function No Runs when a verification fails

A PricingRule takes one of these shapes:

{ type: "subscription"; plan: string }
{ type: "one-time"; amount: number; token?: string }
app.use("/api/v1", hoodlayer.paymentGate({
  pricing: [
    { type: "subscription", plan: plan.id },
    { type: "one-time", amount: 500_000 },
  ],
  onSuccess: (req, info) => {
    req.paymentInfo = info; // stash on the request so downstream handlers can read it
  },
}));

On authenticated requests, the middleware attaches a req.payment object holding the payment details (subscription ID, wallet address, payment proof, and so on).


hoodlayer.verifySubscription()

Checks whether a wallet holds an active subscription to a plan.

const valid = await hoodlayer.verifySubscription(options: {
  subscriber: string;
  plan: string;
}): Promise<boolean>
const isActive = await hoodlayer.verifySubscription({
  subscriber: req.headers["x-wallet-address"],
  plan: plan.id,
});

hoodlayer.verifyPaymentProof()

Checks a payment proof taken from the X-PAYMENT header.

const result = await hoodlayer.verifyPaymentProof(
  proof: string
): Promise<PaymentProofResult>

PaymentProofResult

Field Type Description
valid boolean True if the proof checks out
txHash string Hash of the on-chain transaction
amount number How much was paid, in base units
payer string Wallet address of the payer
memo string The memo carried over from the original payment request

hoodlayer.buildPaymentRequired()

Builds a correctly shaped 402 Payment Required response body.

const body = hoodlayer.buildPaymentRequired(options: {
  pricing: PricingRule[];
  memo?: string;
}): PaymentRequiredResponse

Handy when you’re not using the paymentGate middleware:

app.get("/api/v1/data", async (req, res) => {
  const proof = req.headers["x-payment"];

  if (!proof) {
    return res.status(402).json(hoodlayer.buildPaymentRequired({
      pricing: [{ type: "subscription", plan: plan.id }],
    }));
  }

  const result = await hoodlayer.verifyPaymentProof(proof);
  if (!result.valid) {
    return res.status(402).json(hoodlayer.buildPaymentRequired({
      pricing: [{ type: "subscription", plan: plan.id }],
    }));
  }

  res.json({ data: "..." });
});

hoodlayer.collectAll()

Kicks off collection for every active subscriber on a plan. Usually run from a cron job or some other scheduled task.

const result = await hoodlayer.collectAll(options: {
  plan: string;
  dryRun?: boolean;
}): Promise<CollectResult>

CollectResult

Field Type Description
collected number How many collections succeeded
failed number How many collections failed
totalAmount number USDC collected in total, in base units
failures CollectFailure[] Per-failure details

hoodlayer.collect()

Runs collection for one specific subscription.

await hoodlayer.collect(options: { subscriptionId: string }): Promise<CollectResult>

hoodlayer.listSubscribers()

Fetches everyone subscribed to a plan.

const subscribers = await hoodlayer.listSubscribers(options: {
  plan: string;
  status?: SubscriptionStatus;
}): Promise<Subscription[]>

hoodlayer.deductAllowance()

Debits a subscriber’s allowance. This is the building block for metered billing.

const result = await hoodlayer.deductAllowance(options: {
  allowanceId: string;
  amount: number;
  memo?: string;
}): Promise<{ remaining: number; txHash: string }>

hoodlayer.parseWebhookPayload()

Verifies and parses an incoming webhook payload. More in Webhooks.

const event = hoodlayer.parseWebhookPayload(options: {
  payload: string;
  signature: string;
}): WebhookEvent