Skip to main content

Subscriptions API

Create recurring payment plans with automated billing cycles. Perfect for SaaS, memberships, and subscription services.

Quick Start

  1. Create a subscription plan with your pricing and billing interval
  2. Subscribe customers using their wallet address
  3. ZendFi automatically bills customers at each interval
  4. Receive webhook events for all subscription lifecycle changes

That's it! No manual billing, no payment tracking - we handle everything automatically. 🎉

Features

  • Flexible Billing Intervals - Daily, weekly, monthly, or yearly
  • Free Trials - Offer trial periods before billing starts
  • Automatic Billing - Background worker handles all recurring charges
  • Cycle Limits - Set maximum billing cycles or unlimited
  • Customer Tracking - View all subscriptions per customer wallet
  • Webhook Events - Real-time notifications for all lifecycle events

Common Use Cases

Use CaseDescription
SaaS PlatformsMonthly/yearly subscriptions for software access
Online CoursesMonthly memberships for educational content
Gaming ServicesPremium memberships for game servers
Content CreatorsPatreon-style subscriptions for exclusive content

Create Subscription Plan

Create a reusable subscription plan that customers can subscribe to.

Endpoint

POST /api/v1/subscription-plans

Authentication

Authorization: Bearer YOUR_API_KEY

Request Parameters

ParameterTypeRequiredDescription
namestringYesPlan name (e.g., "Premium Monthly")
descriptionstringNoPlan description
amountnumberYesPrice per billing cycle in USD
currencystringNoCurrency code (default: "USD")
intervalstringYes"daily", "weekly", "monthly", or "yearly"
interval_countnumberNoNumber of intervals between charges (default: 1)
trial_daysnumberNoFree trial days before first charge (default: 0)
metadataobjectNoCustom key-value pairs

Example: Monthly SaaS Plan with Trial

import { ZendFiClient } from '@zendfi/sdk';

const zendfi = new ZendFiClient({
apiKey: process.env.ZENDFI_API_KEY,
});

const plan = await zendfi.createSubscriptionPlan({
name: 'Pro Plan - Monthly',
description: 'Full access to all pro features',
amount: 29.99,
interval: 'monthly',
interval_count: 1,
trial_days: 14,
metadata: {
features: ['unlimited_api_calls', 'priority_support', 'advanced_analytics'],
tier: 'pro',
},
});

console.log('Plan ID:', plan.id);
console.log('Subscription URL:', plan.subscription_url);

Response:

{
"id": "plan_abc123def456",
"merchant_id": "merchant_xyz789",
"name": "Pro Plan - Monthly",
"description": "Full access to all pro features",
"amount": 29.99,
"currency": "USD",
"billing_interval": "Monthly",
"interval_count": 1,
"trial_days": 14,
"max_cycles": null,
"is_active": true,
"created_at": "2025-10-26T12:10:00Z",
"subscription_url": "/subscribe/plan_abc123def456"
}

Example: Annual Plan with Discount

const annualPlan = await zendfi.createSubscriptionPlan({
name: 'Pro Plan - Annual',
description: 'Save 20% with annual billing!',
amount: 287.90,
interval: 'yearly',
metadata: {
annual_discount: '20%',
monthly_equivalent: 23.99,
},
});

// Annual plan saves customers 20%

Get Subscription Plan

Get details of a specific subscription plan. This is a public endpoint - no authentication required.

Endpoint

GET /api/v1/subscription-plans/:plan_id

Example

const plan = await zendfi.getSubscriptionPlan('plan_abc123def456');

console.log('Plan:', plan.name);
console.log('Price:', `$${plan.amount}/${plan.billing_interval.toLowerCase()}`);
console.log('Trial:', plan.trial_days ? `${plan.trial_days} days` : 'No trial');

Subscribe Customer to Plan

Create a subscription for a customer on a specific plan.

Endpoint

POST /api/v1/subscriptions

Request Parameters

ParameterTypeRequiredDescription
plan_idUUIDYesSubscription plan ID
customer_walletstringYesCustomer's Solana wallet address
customer_emailstringNoCustomer's email for notifications
metadataobjectNoCustom key-value pairs

Example

const subscription = await zendfi.createSubscription({
plan_id: 'plan_abc123def456',
customer_wallet: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',
customer_email: 'customer@example.com',
metadata: {
user_id: 'user_12345',
signup_source: 'landing_page',
},
});

console.log('Subscription ID:', subscription.id);
console.log('Status:', subscription.status); // "Trialing" or "Active"
if (subscription.trial_end) {
console.log('Trial ends:', subscription.trial_end);
}

Response:

{
"id": "sub_xyz789abc123",
"plan_id": "plan_abc123def456",
"plan_name": "Pro Plan - Monthly",
"customer_wallet": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"status": "Trialing",
"current_period_start": "2025-10-26T12:10:00Z",
"current_period_end": "2025-11-09T12:10:00Z",
"next_payment_attempt": "2025-11-09T12:10:00Z",
"cycles_completed": 0,
"trial_end": "2025-11-09T12:10:00Z",
"created_at": "2025-10-26T12:10:00Z",
"payment_url": null
}
Trial Period Behavior

If the plan has trial_days > 0, the subscription status will be "Trialing" and payment_url will be null. The first payment happens automatically after the trial ends!

Get Subscription

Get details of a specific subscription.

Endpoint

GET /api/v1/subscriptions/:id

Example

const subscription = await zendfi.getSubscription('sub_xyz789abc123');

console.log('Status:', subscription.status);
console.log('Next payment:', subscription.next_payment_attempt);
console.log('Cycles completed:', subscription.cycles_completed);

Response:

{
"id": "sub_xyz789abc123",
"plan_id": "plan_abc123def456",
"plan_name": "Pro Plan - Monthly",
"customer_wallet": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"status": "Active",
"current_period_start": "2025-11-09T12:10:00Z",
"current_period_end": "2025-12-09T12:10:00Z",
"next_payment_attempt": "2025-12-09T12:10:00Z",
"cycles_completed": 1,
"trial_end": null,
"created_at": "2025-10-26T12:10:00Z",
"payment_url": "https://checkout.zendfi.tech/subscription/sub_xyz789abc123/pay"
}

Create Subscription Payment

Create a payment for a subscription's current billing cycle. Used by customers to pay their subscription bill.

Endpoint

POST /api/v1/subscriptions/:id/pay

Example

// Customer initiates payment for their subscription
const payment = await zendfi.request('POST', `/api/v1/subscriptions/${subscriptionId}/pay`);

console.log('Payment created:', payment.id);
console.log('Payment URL:', payment.payment_url);

Response:

Returns a payment object with payment URL for the customer to complete payment.

Cancel Subscription

Cancel a subscription immediately or at the end of the current billing period.

Endpoint

POST /api/v1/subscriptions/:id/cancel

Request Parameters

ParameterTypeRequiredDescription
cancel_at_period_endbooleanNoIf true, continues until period ends (default: false)
cancellation_reasonstringNoCancellation reason for your records

Example: Cancel Immediately

// Cancel immediately (SDK method doesn't support options - use direct request)
const response = await zendfi.cancelSubscription('sub_xyz789abc123');

console.log('Cancelled:', response);

Example: Cancel at Period End

// Let customer finish the current billing period
// Use direct API request for full control
const response = await zendfi.request('POST', `/api/v1/subscriptions/${subscriptionId}/cancel`, {
cancel_at_period_end: true,
cancellation_reason: 'Switching to annual plan',
});

// Status remains "Active" until period ends
console.log('Will cancel at:', response.current_period_end);

Subscription Statuses

StatusDescriptionAction
TrialingIn free trial periodGrant full access, remind of trial end date
ActiveBilling normallyGrant full access
PastDueLast payment failedShow payment reminder, limited grace period
PausedTemporarily pausedLimited or no access
CancelledCancelled by customer/merchantRevoke access, offer win-back incentives
ExpiredReached max_cycles or natural endRevoke access, offer renewal

Automatic Billing

ZendFi handles all subscription billing automatically. Our background worker:

  1. Runs every hour to check for subscriptions with next_payment_attempt due
  2. Creates a payment for the billing amount
  3. Generates a payment link for the customer
  4. Sends webhook event SubscriptionPaymentFailed if payment fails
  5. On successful payment: Advances billing cycle and sends SubscriptionRenewed
  6. On failed payment: Marks subscription PastDue and retries later
No Manual Work Required

You just create subscriptions and we handle everything else!

Webhook Events

EventDescription
SubscriptionCreatedCustomer subscribed to a plan
SubscriptionRenewedSuccessful billing cycle payment
SubscriptionPaymentFailedPayment failed
SubscriptionCancelledSubscription cancelled

Example Webhook Payload

{
"event_type": "SubscriptionRenewed",
"timestamp": "2025-11-09T12:10:05Z",
"subscription": {
"id": "sub_xyz789abc123",
"plan_id": "plan_abc123def456",
"plan_name": "Pro Plan - Monthly",
"customer_wallet": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
"status": "Active",
"current_period_start": "2025-11-09T12:10:00Z",
"current_period_end": "2025-12-09T12:10:00Z",
"cycles_completed": 1,
"next_payment_attempt": "2025-12-09T12:10:00Z",
"trial_end": null,
"created_at": "2025-10-26T12:10:00Z"
}
}

Next Steps

Ready to integrate subscriptions?

Explore more features:

Need help?

Ask AI about the docs...