Provider SDK
Complete reference for the RecurProvider class. Use this when building a service that accepts payments from agents.
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