Subscriptions API
The Subscriptions API allows you to create and manage recurring billing subscriptions for your customers.
Methods
getSubscriptions
Retrieve a list of all subscriptions with optional pagination.
const { getSubscriptions } = useEasy();
const result = await getSubscriptions({
limit: 50,
offset: 0,
});
Parameters
params(optional)limit(number): Maximum number of subscriptions to return (default: 10, max: 100)offset(number): Number of subscriptions to skip for pagination
Returns
ApiResponse<SubscriptionData[]>;
Example
import { useEasy } from "@easylabs/react";
import { useState, useEffect } from "react";
function SubscriptionList() {
const { getSubscriptions } = useEasy();
const [subscriptions, setSubscriptions] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchSubscriptions = async () => {
try {
const result = await getSubscriptions({ limit: 50 });
setSubscriptions(result.data);
} catch (error) {
console.error("Failed to fetch subscriptions:", error);
} finally {
setLoading(false);
}
};
fetchSubscriptions();
}, [getSubscriptions]);
if (loading) return <div>Loading...</div>;
return (
<ul>
{subscriptions.map((sub) => (
<li key={sub.id}>
Subscription {sub.id} - Status: {sub.status}
</li>
))}
</ul>
);
}
getSubscription
Retrieve a specific subscription by ID.
const { getSubscription } = useEasy();
const result = await getSubscription("sub_123");
const subscription = result.data;
Parameters
subscriptionId(string, required): The ID of the subscription to retrieve
Returns
ApiResponse<SubscriptionData>;
Example
import { useEasy } from "@easylabs/react";
import { useState, useEffect } from "react";
function SubscriptionDetails({ subscriptionId }) {
const { getSubscription } = useEasy();
const [subscription, setSubscription] = useState(null);
useEffect(() => {
const fetchSubscription = async () => {
try {
const result = await getSubscription(subscriptionId);
setSubscription(result.data);
} catch (error) {
console.error("Subscription not found:", error);
}
};
fetchSubscription();
}, [subscriptionId, getSubscription]);
if (!subscription) return <div>Loading...</div>;
return (
<div>
<h2>Subscription {subscription.id}</h2>
<p>Status: {subscription.status}</p>
<p>
Current Period:{" "}
{new Date(subscription.current_period_start).toLocaleDateString()} -{" "}
{new Date(subscription.current_period_end).toLocaleDateString()}
</p>
{subscription.cancel_at_period_end && (
<p>
<strong>Will cancel at period end</strong>
</p>
)}
</div>
);
}
createSubscription
Create a new subscription for a customer.
const { createSubscription } = useEasy();
const result = await createSubscription({
identity_id: "cust_123",
items: [{ price_id: "price_abc", quantity: 1 }],
trial_period_days: 14,
metadata: {
plan: "premium",
},
});
Parameters
params(required)identity_id(string, required): Customer IDitems(array, required): Array of subscription itemsprice_id(string): Price IDquantity(number): Quantity (default: 1)
trial_period_days(number, optional): Number of days for trial periodmetadata(object, optional): Additional custom data
Returns
ApiResponse<SubscriptionData>;
Example
import { useEasy } from "@easylabs/react";
import { useState } from "react";
function CreateSubscriptionForm({ customerId }) {
const { createSubscription } = useEasy();
const [priceId, setPriceId] = useState("");
const [trial, setTrial] = useState(false);
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const result = await createSubscription({
identity_id: customerId,
items: [{ price_id: priceId, quantity: 1 }],
trial_period_days: trial ? 14 : undefined,
metadata: {
source: "web",
},
});
console.log("Subscription created:", result.data.id);
} catch (error) {
console.error("Failed to create subscription:", error);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<select
value={priceId}
onChange={(e) => setPriceId(e.target.value)}
required
>
<option value="">Select Plan</option>
<option value="price_monthly">Monthly - $29.99</option>
<option value="price_annual">Annual - $299.99</option>
</select>
<label>
<input
type="checkbox"
checked={trial}
onChange={(e) => setTrial(e.target.checked)}
/>
Start with 14-day trial
</label>
<button type="submit" disabled={loading}>
{loading ? "Creating..." : "Subscribe"}
</button>
</form>
);
}
updateSubscription
Update an existing subscription.
const { updateSubscription } = useEasy();
const result = await updateSubscription("sub_123", {
items: [{ price_id: "price_new", quantity: 1 }],
metadata: {
upgraded: true,
},
});
Parameters
subscriptionId(string, required): The ID of the subscription to updateparams(required)items(array, optional): New subscription itemsmetadata(object, optional): Updated metadata
Returns
ApiResponse<SubscriptionData>;
Updating subscription items will prorate charges and adjust billing accordingly. The change takes effect immediately.
Example
import { useEasy } from "@easylabs/react";
import { useState } from "react";
function UpgradeSubscription({ subscriptionId, currentPriceId }) {
const { updateSubscription } = useEasy();
const [newPriceId, setNewPriceId] = useState("");
const handleUpgrade = async () => {
try {
const result = await updateSubscription(subscriptionId, {
items: [{ price_id: newPriceId, quantity: 1 }],
metadata: {
upgraded_from: currentPriceId,
upgraded_at: new Date().toISOString(),
},
});
console.log("Subscription upgraded:", result.data);
} catch (error) {
console.error("Failed to upgrade:", error);
}
};
return (
<div>
<h3>Upgrade Your Plan</h3>
<select
value={newPriceId}
onChange={(e) => setNewPriceId(e.target.value)}
>
<option value="price_pro">Pro - $49.99/month</option>
<option value="price_enterprise">Enterprise - $99.99/month</option>
</select>
<button onClick={handleUpgrade}>Upgrade Now</button>
</div>
);
}
cancelSubscription
Cancel a subscription at the end of the current billing period.
const { cancelSubscription } = useEasy();
const result = await cancelSubscription("sub_123");
Parameters
subscriptionId(string, required): The ID of the subscription to cancel
Returns
ApiResponse<SubscriptionData>;
The subscription will remain active until the end of the current billing period. The customer retains access until that date.
Example
import { useEasy } from "@easylabs/react";
import { useState } from "react";
function CancelSubscriptionButton({ subscriptionId, onCancelled }) {
const { cancelSubscription } = useEasy();
const [confirming, setConfirming] = useState(false);
const handleCancel = async () => {
if (!confirming) {
setConfirming(true);
setTimeout(() => setConfirming(false), 5000); // Reset after 5 seconds
return;
}
try {
const result = await cancelSubscription(subscriptionId);
console.log("Subscription cancelled:", result.data);
onCancelled();
} catch (error) {
console.error("Failed to cancel:", error);
}
};
return (
<button onClick={handleCancel} style={{ color: "red" }}>
{confirming
? "Click again to confirm cancellation"
: "Cancel Subscription"}
</button>
);
}
reactivateSubscription
Reactivate a cancelled subscription before the period ends.
const { reactivateSubscription } = useEasy();
const result = await reactivateSubscription("sub_123");
Parameters
subscriptionId(string, required): The ID of the subscription to reactivate
Returns
ApiResponse<SubscriptionData>;
This only works if the subscription was cancelled but the current billing period hasn't ended yet. After the period ends, you'll need to create a new subscription.
Example
import { useEasy } from "@easylabs/react";
function ReactivateSubscriptionButton({ subscriptionId }) {
const { reactivateSubscription } = useEasy();
const handleReactivate = async () => {
try {
const result = await reactivateSubscription(subscriptionId);
console.log("Subscription reactivated:", result.data);
} catch (error) {
console.error("Failed to reactivate:", error);
}
};
return (
<button onClick={handleReactivate} style={{ color: "green" }}>
Reactivate Subscription
</button>
);
}
Type Definitions
SubscriptionData
interface SubscriptionData {
id: string;
identity_id: string;
status: SubscriptionStatus;
items: SubscriptionItem[];
current_period_start: string;
current_period_end: string;
cancel_at_period_end: boolean;
canceled_at?: string;
ended_at?: string;
trial_start?: string;
trial_end?: string;
metadata?: Record<string, unknown>;
created_at: string;
updated_at: string;
}
SubscriptionStatus
type SubscriptionStatus =
| "active" // Subscription is active and billing
| "canceled" // Subscription has been cancelled
| "incomplete" // Initial payment failed
| "incomplete_expired" // Initial payment failed and grace period expired
| "past_due" // Payment failed but retrying
| "paused" // Subscription is paused
| "trialing" // In trial period
| "unpaid"; // Payment failed and retries exhausted
SubscriptionItem
interface SubscriptionItem {
id: string;
price_id: string;
quantity: number;
}
CreateSubscriptionParams
interface CreateSubscriptionParams {
identity_id: string;
items: Array<{
price_id: string;
quantity?: number;
}>;
trial_period_days?: number;
metadata?: Record<string, unknown>;
}
Subscription Lifecycle
┌─────────┐
│ Created │
└────┬────┘
│
▼
┌──────────┐ ┌──────────┐
│ Trialing │───▶│ Active │
└──────────┘ └────┬─────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌──────────┐ ┌──────────┐
│Past Due │ │ Canceled │ │ Paused │
└─────────┘ └──────────┘ └──────────┘
│ │
▼ ▼
┌────────┐ ┌────────┐
│ Unpaid │ │ Ended │
└────────┘ └────────┘
Common Patterns
Subscription with Trial
const result = await createSubscription({
identity_id: "cust_123",
items: [{ price_id: "price_monthly", quantity: 1 }],
trial_period_days: 14,
});
Multiple Items (Metered Billing)
const result = await createSubscription({
identity_id: "cust_123",
items: [
{ price_id: "price_base", quantity: 1 },
{ price_id: "price_addon1", quantity: 5 },
{ price_id: "price_addon2", quantity: 3 },
],
});
Upgrade/Downgrade
// Upgrade to higher tier
await updateSubscription("sub_123", {
items: [{ price_id: "price_premium", quantity: 1 }],
});
// Downgrade to lower tier
await updateSubscription("sub_123", {
items: [{ price_id: "price_basic", quantity: 1 }],
});
Error Handling
try {
const result = await createSubscription({ ... });
} catch (error) {
if (error.message.includes('payment method')) {
console.error('No valid payment method');
} else if (error.message.includes('price')) {
console.error('Invalid price ID');
} else if (error.message.includes('customer')) {
console.error('Customer not found');
} else {
console.error('Subscription creation failed:', error);
}
}
Best Practices
- Always show trial periods clearly to customers
- Send email notifications for subscription changes
- Handle failed payments gracefully with retry logic
- Allow easy cancellation to build trust
- Prorate upgrades/downgrades fairly
- Show upcoming charges before billing
- Keep payment methods updated to avoid failures
Next Steps
This documentation is being migrated from the DEVELOPER_DOCS.md file.
For complete documentation, please see:
Coming soon to this documentation site!