Installation

npm install @recur/sdk

RecurProvider

import { RecurProvider } from "@recur/sdk";

const recur = new RecurProvider(config: RecurProviderConfig);

RecurProviderConfig

Option Type Required Description
wallet Keypair \| Signer Yes Provider’s Solana wallet
apiKey string Yes Recur API key from the Dashboard
network "mainnet-beta" \| "devnet" Yes Solana network
rpcUrl string No Custom Solana RPC endpoint
facilitatorUrl string No Custom Facilitator URL
webhookSecret string No Secret for verifying incoming webhook signatures

Methods

recur.createPlan()

Creates a Plan account on the Recur Plan Registry. Immutable after creation.

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

CreatePlanOptions

Option Type Required Description
name string Yes Display name for the plan
amount number Yes Price per billing cycle, in token base units
interval BillingInterval Yes "MONTHLY" \| "WEEKLY" \| "DAILY" \| "PER_REQUEST"
token string No SPL token mint (default: USDC)
trialPeriodDays number No Free trial length in days
meteredOverage MeteredOverage No Usage-based overage billing config
const plan = await recur.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); // PublicKey — persist this as your plan address

recur.deprecatePlan()

Marks a plan as deprecated so no new subscriptions can be created. Existing subscriptions continue.

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

recur.paymentGate()

Express/Node.js middleware that gates routes behind payment. Returns a 402 response to unauthenticated requests and passes through requests with valid payment proofs or active subscriptions.

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

PaymentGateOptions

Option Type Required Description
pricing PricingRule[] Yes Payment options to offer
onSuccess function No Callback after successful verification. Receives (req, paymentInfo).
onFailure function No Callback for failed verifications

PricingRule is one of:

{ type: "subscription"; plan: string }
{ type: "one-time"; amount: number; token?: string }
app.use("/api/v1", recur.paymentGate({
  pricing: [
    { type: "subscription", plan: plan.id },
    { type: "one-time", amount: 500_000 },
  ],
  onSuccess: (req, info) => {
    req.paymentInfo = info; // attach to request for downstream handlers
  },
}));

The middleware adds a req.payment object to authenticated requests with the payment details (subscription ID, wallet address, payment proof, etc.).


recur.verifySubscription()

Verifies that a wallet has an active subscription to a plan.

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

recur.verifyPaymentProof()

Verifies a payment proof from the X-PAYMENT header.

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

PaymentProofResult

Field Type Description
valid boolean Whether the proof is valid
txSignature string On-chain transaction signature
amount number Amount paid, in base units
payer string Payer wallet address
memo string Memo from the original payment request

recur.buildPaymentRequired()

Constructs a properly formatted 402 Payment Required response body.

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

Useful if you are 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(recur.buildPaymentRequired({
      pricing: [{ type: "subscription", plan: plan.id }],
    }));
  }

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

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

recur.collectAll()

Triggers collection for all active subscribers on a plan. Typically called from a cron job or scheduled task.

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

CollectResult

Field Type Description
collected number Number of successful collections
failed number Number of failed collections
totalAmount number Total USDC collected, in base units
failures CollectFailure[] Details on each failure

recur.collect()

Triggers collection for a single subscription.

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

recur.listSubscribers()

Returns all subscribers to a plan.

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

recur.deductAllowance()

Draws down against a subscriber’s allowance. Used for metered billing.

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

recur.parseWebhookPayload()

Parses and verifies an incoming webhook payload. See Webhooks.

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