Installation

npm install @recur/sdk

RecurAgent

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

const agent = new RecurAgent(config: RecurAgentConfig);

RecurAgentConfig

Option Type Required Description
wallet Keypair \| Signer Yes Solana keypair or compatible signer
network "mainnet-beta" \| "devnet" Yes Solana network
rpcUrl string No Custom Solana RPC endpoint
facilitatorUrl string No Custom Facilitator URL (default: Recur’s hosted Facilitator)
defaultToken string No Default SPL token mint (default: USDC)

Wallets

The wallet option accepts:

  • A standard Keypair from @solana/web3.js
  • Any object implementing the Signer interface: { publicKey: PublicKey, signTransaction(tx): Promise<Transaction> }

This means you can pass signers from Privy, Dynamic, Turnkey, or any other embedded wallet provider.

// Standard keypair
import { Keypair } from "@solana/web3.js";
const agent = new RecurAgent({ wallet: keypair, network: "mainnet-beta" });

// Privy embedded wallet
const agent = new RecurAgent({ wallet: privySigner, network: "mainnet-beta" });

Methods

agent.pay()

Makes a one-time payment via the x402 flow. Handles the full request-402-pay-retry cycle.

const result = await agent.pay(options: PayOptions): Promise<PayResult>

PayOptions

Option Type Required Description
url string Yes The URL of the resource to pay for
method string No HTTP method (default: "GET")
body object No Request body for POST requests
headers object No Additional request headers
maxAmount number No Maximum amount to pay, in token base units. Rejects if the service requests more.
token string No SPL token mint to pay with (default: USDC)

PayResult

Field Type Description
data any Parsed response body from the API
status number HTTP status code
headers object Response headers
txSignature string Solana transaction signature
amountPaid number Actual amount paid, in token base units
const result = await agent.pay({
  url: "https://api.example.com/v1/data",
  maxAmount: 1_000_000, // reject if service asks for more than 1 USDC
});

console.log(result.data);        // response body
console.log(result.txSignature); // on-chain proof

agent.subscribe()

Creates an on-chain subscription to a plan and delegates billing authority to the service provider.

const sub = await agent.subscribe(options: SubscribeOptions): Promise<Subscription>

SubscribeOptions

Option Type Required Description
planId string Yes On-chain plan address
maxOveragePerCycle number No Spend cap for metered overage per billing cycle
token string No Override the plan’s default token

Returns: a Subscription object. See Subscriptions for the full structure.

const sub = await agent.subscribe({
  planId: "7xKp...plan_address",
  maxOveragePerCycle: 10_000_000, // authorize up to 10 USDC in overage
});

console.log(sub.id);            // on-chain subscription address
console.log(sub.status);        // "ACTIVE" or "TRIAL"
console.log(sub.nextBillingAt); // Unix timestamp

agent.cancelSubscription()

Cancels an active subscription. On-chain and immediate.

await agent.cancelSubscription(options: { subscriptionId: string }): Promise<void>

agent.listSubscriptions()

Returns all subscriptions for the agent’s wallet.

const subs = await agent.listSubscriptions(
  options?: { status?: SubscriptionStatus }
): Promise<Subscription[]>

agent.createAllowance()

Creates a metered spend cap. See Allowances.

const allowance = await agent.createAllowance(options: AllowanceOptions): Promise<Allowance>

AllowanceOptions

Option Type Required Description
grantee string Yes Wallet address of the service being authorized
maxAmount number Yes Total spend cap, in token base units
token string No SPL token mint (default: USDC)
expiresAt number No Unix timestamp for expiry

agent.revokeAllowance()

Revokes an allowance before it expires.

await agent.revokeAllowance(options: { allowanceId: string }): Promise<void>

agent.getAllowance()

Returns the current state of an allowance.

const status = await agent.getAllowance(
  options: { allowanceId: string }
): Promise<Allowance>

Error handling

The SDK throws typed errors for all failure cases:

import {
  InsufficientFundsError,
  PaymentRejectedError,
  AllowanceExhaustedError,
  FacilitatorError,
} from "@recur/sdk/errors";

try {
  await agent.pay({ url: "...", maxAmount: 1_000_000 });
} catch (e) {
  if (e instanceof InsufficientFundsError) {
    console.error("Wallet needs more USDC", e.required, e.available);
  } else if (e instanceof PaymentRejectedError) {
    console.error("Service rejected payment proof", e.reason);
  } else if (e instanceof FacilitatorError) {
    console.error("Facilitator error", e.statusCode, e.message);
  }
}
Error class Cause
InsufficientFundsError Wallet balance below required amount
PaymentRejectedError Service rejected the payment proof
MaxAmountExceededError Service requested more than maxAmount
AllowanceExhaustedError Spend cap reached
SubscriptionNotActiveError Subscription is paused or cancelled
FacilitatorError Facilitator returned an error
SolanaTransactionError On-chain transaction failed