NodeRailsCRYPTO PAYMENT INFRASTRUCTURE
DocumentationAPI Reference
Dashboard

Subscriptions

Subscriptions enable recurring crypto payments. Create a product plan with a price, then subscribe customers to it.

Full flow

Step 1: Create a product plan and price

A subscription requires a product plan with at least one price. Plans define what you're selling, and prices define how much and how often the customer is billed.

Set up your producttypescript
// Create a product plan
const plan = await noderails.productPlans.create({
  name: 'Pro Plan',
  description: 'Full access to all features',
  planType: 'SUBSCRIPTION',
  prices: [
    {
      amount: '29.99',
      billingInterval: 'MONTH',
      billingIntervalCount: 1,
      nickname: 'Monthly',
      isDefault: true,
    },
  ],
});

const monthlyPrice = plan.prices![0];

// Add an annual price (optional)
const annualPrice = await noderails.productPlans.createPrice(plan.id, {
  amount: '299.00',
  currency: 'USD',
  billingInterval: 'YEAR',
  billingIntervalCount: 1,
  nickname: 'Annual',
});
💡

Product Plans

See the Product Plans page for full details on creating and managing product plans and their prices.

Step 2: Create a customer

Create a customertypescript
const customer = await noderails.customers.create({
  email: 'alice@example.com',
  name: 'Alice',
  walletAddress: '0x...',   // Optional: their wallet address
});

Step 3: Create the subscription

Subscribe the customertypescript
const subscription = await noderails.subscriptions.create({
  customerAccountId: customer.id,
  productPlanId: plan.id,
  productPlanPriceId: monthlyPrice.id,
});

console.log(subscription.id);              // Subscription ID
console.log(subscription.status);          // "CREATED"
console.log(subscription.currentPeriodEnd); // Next billing date

Step 4: Create checkout for initial authorization

Create subscription checkouttypescript
const checkout = await noderails.subscriptions.createCheckout(subscription.id);
console.log(checkout.id); // Checkout session ID
// Redirect customer to hosted checkout:
// https://pay.noderails.com/checkout/${checkout.id}

Pause a subscription

Temporarily pause billing. The customer keeps access until the current period ends.

Pausetypescript
await noderails.subscriptions.pause('sub-id');

Resume a subscription

Resumetypescript
await noderails.subscriptions.resume('sub-id');

Cancel a subscription

Canceltypescript
// Cancel at end of current period (customer keeps access until then)
await noderails.subscriptions.cancel('sub-id', {
  cancelAtPeriodEnd: true,
});

// Cancel immediately
await noderails.subscriptions.cancel('sub-id', {
  cancelAtPeriodEnd: false,
});

List subscriptions

List and filtertypescript
// List all active subscriptions
const subs = await noderails.subscriptions.list({ status: 'ACTIVE' });

for (const sub of subs.data) {
  console.log(sub.id, sub.status, sub.currentPeriodEnd);
}

Retrieve a subscription

When you retrieve a subscription, the response includes the last 10 invoices. Each paid invoice includes its full payment intent with on-chain transaction details.

Retrieve with payment detailstypescript
const sub = await noderails.subscriptions.retrieve('sub-id');
console.log(sub.status);           // "ACTIVE" | "PAUSED" | "CANCELLED"
console.log(sub.currentPeriodEnd); // Next billing date

// Each invoice includes its payment intent
for (const invoice of sub.invoices ?? []) {
  console.log(invoice.status);                              // "PAID"
  if (invoice.paymentIntent) {
    console.log(invoice.paymentIntent.status);               // "SETTLED"
    console.log(invoice.paymentIntent.captureTxHash);        // "0x..."
    console.log(invoice.paymentIntent.authorizationTokenKey); // "USDC-8453"
  }
}

Webhooks

EventDescription
subscription.createdSubscription was created
subscription.activatedSubscription became active
subscription.renewedRecurring payment was collected
subscription.cancelledSubscription was cancelled
subscription.pausedSubscription was paused
subscription.resumedSubscription was resumed

Methods reference

MethodDescription
create(params)Create a new subscription
retrieve(id)Retrieve a subscription by ID
list(params?)List subscriptions with optional filters
pause(id)Pause billing
resume(id)Resume a paused subscription
cancel(id, params?)Cancel a subscription
createCheckout(id)Create a hosted checkout session for initial authorization

TypeScript types

Type importstypescript
import type {
  Subscription,
  SubscriptionCreateParams,
  SubscriptionListParams,
} from '@noderails/sdk';

Response body reference

All responses are wrapped in { success: true, data: ... }. The fields below describe what's inside data.

create() response

Subscription (create)

idstringUnique subscription ID (UUID)
appIdstringYour app ID
customerAccountIdstringCustomer being subscribed
productPlanIdstringProduct plan ID
productPlanPriceIdstringPrice ID
statusstring"CREATED" or "TRIALING"
customerWalletIdnullSet after customer authorizes
authorizationMethodnullNATIVE, PERMIT, or EIP7702
authorizationChainIdnullChain selected for payments
authorizationTokenKeynullToken selected for payments
permitSignaturenullPermit signature if applicable
permitDeadlinenullPermit deadline if applicable
permitNoncenullPermit nonce if applicable
approvedAllowancenullERC-20 allowance amount
currentPeriodStartstringCurrent billing period start
currentPeriodEndstringCurrent billing period end
billingCycleAnchorstringAnchor date for billing
trialStartstring | nullTrial start date if applicable
trialEndstring | nullTrial end date if applicable
cancelAtnullScheduled cancellation date
cancelledAtnullWhen the subscription was cancelled
cancelAtPeriodEndbooleanWhether cancel is deferred to period end
pausedAtnullWhen the subscription was paused
pastDueSincenullWhen subscription entered past-due state
captureRetryCountnumberCurrent retry count for payments
maxCaptureRetriesnumberMax retries before cancellation
allowedChainsstring | number[]"ALL" or array of chain IDs
allowedTokensstring | string[]"ALL" or array of token keys
metadataobjectYour metadata key-value pairs
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last update timestamp
productPlanProductPlanFull product plan object
productPlanPriceProductPlanPriceFull price object

retrieve() response

Returns all fields from create() above, plus these additional nested objects. This is the most complete response:

Additional fields on retrieve

appAppFull app object
productPlan.taxRateTaxRate | nullTax rate on the plan
customerAccountCustomerAccountFull customer object
customerWalletCustomerWallet | nullWallet used for payments (with chain info)
invoicesInvoice[]Last 10 invoices (descending by date)
💡

Invoices are richly nested

Each invoice in invoices[] includes its own taxRate, items[] (with each item's taxRate), and paymentIntent (full payment intent object). This gives you complete billing history with on-chain tx details in a single call.

list() response

Returns a lighter response than retrieve(). Each subscription includesproductPlan (with taxRate), productPlanPrice, and customerAccount. Does not include app, customerWallet, or invoices.

Paginated response shapejson
{
  "success": true,
  "data": [ /* Subscription[] */ ],
  "pagination": {
    "total": 15,
    "page": 1,
    "pageSize": 20,
    "totalPages": 1
  }
}

pause(), resume(), cancel() response

All three return the subscription with scalar fields only (no relations). Key fields that change:

State changes per action

pause → statusstring"PAUSED", pausedAt is set
resume → statusstring"ACTIVE", pausedAt is cleared, new period dates set
cancel → statusstring"CANCELLED" (immediate) or unchanged (if cancelAtPeriodEnd=true)
cancel → cancelAtPeriodEndbooleantrue if deferred, cancelAt is set to period end