Enabling Customers to Cancel Subscriptions

Learn how to implement subscription cancellation for your customers.

Overview

Allowing customers to cancel their subscriptions is essential for a good user experience and helps reduce chargebacks. Coinflow provides simple APIs to enable subscription cancellation in two ways:

Cancellation Methods

Two Approaches to Cancellation

  1. Customer-Initiated Cancellation - Customers cancel through your application using their session key
  2. Merchant-Initiated Cancellation - Merchants cancel on behalf of customers using the merchant API

Customer-Initiated Cancellation

Step 1: Get Customer’s Subscriptions

First, retrieve all active subscriptions for the customer:

1// API Reference: /api-reference/api-reference/customers/get-customersubscriptions
2
3const response = await fetch(
4 'https://api-sandbox.coinflow.cash/api/subscription/{merchantId}/subscribers',
5 {
6 method: 'GET',
7 headers: {
8 'accept': 'application/json',
9 'x-coinflow-auth-session-key': sessionKey
10 }
11 }
12);
13
14const subscriptions = await response.json();

Example Response:

1[
2 {
3 "id": "6851d8c378269da7d5a535d6",
4 "customerId": "customer123",
5 "blockchain": "user",
6 "merchantId": "your-merchant-id",
7 "email": "customer@example.com",
8 "plan": "Premium Plan",
9 "planCode": "premium-monthly",
10 "status": "Active",
11 "createdAt": "2024-01-15T10:30:00Z",
12 "nextBillingDate": "2024-02-15T10:30:00Z"
13 }
14]

Step 2: Cancel the Subscription

Use the subscription ID to cancel:

1// API Reference: /api-reference/api-reference/subscription/cancel-customer-subscription
2
3const response = await fetch(
4 `https://api-sandbox.coinflow.cash/api/subscription/{merchantId}/subscribers/{subscriptionId}`,
5 {
6 method: 'PATCH',
7 headers: {
8 'x-coinflow-auth-session-key': sessionKey
9 }
10 }
11);
12
13if (response.ok) {
14 console.log('Subscription cancelled successfully');
15}

Building a Cancellation UI

Here’s an example React component for subscription cancellation:

1import { useState, useEffect } from 'react';
2
3function SubscriptionManager({ sessionKey, merchantId }) {
4 const [subscriptions, setSubscriptions] = useState([]);
5 const [loading, setLoading] = useState(true);
6
7 useEffect(() => {
8 fetchSubscriptions();
9 }, []);
10
11 const fetchSubscriptions = async () => {
12 try {
13 const response = await fetch(
14 `https://api-sandbox.coinflow.cash/api/subscription/${merchantId}/subscribers`,
15 {
16 headers: {
17 'x-coinflow-auth-session-key': sessionKey
18 }
19 }
20 );
21 const data = await response.json();
22 setSubscriptions(data);
23 } catch (error) {
24 console.error('Error fetching subscriptions:', error);
25 } finally {
26 setLoading(false);
27 }
28 };
29
30 const cancelSubscription = async (subscriptionId) => {
31 if (!confirm('Are you sure you want to cancel this subscription?')) {
32 return;
33 }
34
35 try {
36 const response = await fetch(
37 `https://api-sandbox.coinflow.cash/api/subscription/${merchantId}/subscribers/${subscriptionId}`,
38 {
39 method: 'PATCH',
40 headers: {
41 'x-coinflow-auth-session-key': sessionKey
42 }
43 }
44 );
45
46 if (response.ok) {
47 alert('Subscription cancelled successfully');
48 fetchSubscriptions(); // Refresh the list
49 }
50 } catch (error) {
51 console.error('Error cancelling subscription:', error);
52 alert('Failed to cancel subscription');
53 }
54 };
55
56 if (loading) {
57 return <div>Loading subscriptions...</div>;
58 }
59
60 return (
61 <div>
62 <h2>Your Subscriptions</h2>
63 {subscriptions.map(sub => (
64 <div key={sub.id} className="subscription-card">
65 <h3>{sub.plan}</h3>
66 <p>Status: {sub.status}</p>
67 <p>Next billing: {new Date(sub.nextBillingDate).toLocaleDateString()}</p>
68 {sub.status === 'Active' && (
69 <button onClick={() => cancelSubscription(sub.id)}>
70 Cancel Subscription
71 </button>
72 )}
73 </div>
74 ))}
75 </div>
76 );
77}

Merchant-Initiated Cancellation

Merchants can cancel subscriptions on behalf of customers using the merchant API:

1// API Reference: /api/cancelsubscription
2
3const response = await fetch(
4 `https://api-sandbox.coinflow.cash/api/merchant/subscription/subscribers/{subscriptionId}`,
5 {
6 method: 'PATCH',
7 headers: {
8 'Authorization': 'YOUR_API_KEY',
9 'Content-Type': 'application/json'
10 }
11 }
12);

This is useful for:

  • Customer support scenarios
  • Policy violations
  • Refund situations
  • Account closures

Cancellation via Merchant Dashboard

Merchants can also cancel subscriptions through the Coinflow merchant dashboard:

  1. Log in to merchant dashboard
  2. Navigate to Subscriptions
  3. Click on the subscription plan
  4. Find the subscriber in the list
  5. Click Cancel Subscription
Cancel subscription from merchant dashboard

Cancellation Behavior

What Happens When a Subscription is Cancelled

When a subscription is cancelled:

  • Status Update: Changes to Canceled
  • Billing: No future payments will be processed
  • Access: Customer typically retains access until end of current billing period
  • Notifications: Cancellation webhook is triggered

Configuring Access After Cancellation

You can implement different access policies:

  1. Immediate Termination - Access ends immediately upon cancellation
  2. End of Period - Access continues until the end of the current billing period (recommended)
  3. Grace Period - Custom grace period after cancellation

Implement your preferred policy in your application logic using the cancellation timestamp and next billing date from the subscription data.

Handling Cancellation Webhooks

Set up webhooks to receive cancellation notifications:

1// Webhook payload for subscription cancellation
2{
3 "event": "subscription.cancelled",
4 "data": {
5 "subscriptionId": "6851d8c378269da7d5a535d6",
6 "customerId": "customer123",
7 "planCode": "premium-monthly",
8 "cancelledAt": "2024-01-20T15:45:00Z",
9 "reason": "customer_requested"
10 }
11}

Handle the webhook in your backend:

1app.post('/webhooks/coinflow', (req, res) => {
2 const event = req.body;
3
4 if (event.event === 'subscription.cancelled') {
5 const { subscriptionId, customerId } = event.data;
6
7 // Update your database
8 await db.subscriptions.update({
9 where: { id: subscriptionId },
10 data: { status: 'cancelled', cancelledAt: new Date() }
11 });
12
13 // Send cancellation email to customer
14 await sendCancellationEmail(customerId);
15
16 // Log for analytics
17 analytics.track('Subscription Cancelled', {
18 subscriptionId,
19 customerId
20 });
21 }
22
23 res.sendStatus(200);
24});

Best Practices

Clear Communication

  • Explain what happens when they cancel
  • Show when access will end
  • Offer alternatives (pause, downgrade)
  • Request feedback on why they’re cancelling

Retention Strategies

Before cancelling, consider:

  • Offering a discount or special offer
  • Suggesting a pause instead of cancel
  • Downgrading to a lower tier
  • Providing a feedback form

User Experience

  • Make cancellation easy to find (don’t hide it)
  • Require confirmation but don’t make it difficult
  • Send confirmation email after cancellation
  • Allow easy reactivation

Example Cancellation Flow

1function CancellationFlow({ subscription, onCancel }) {
2 const [step, setStep] = useState('confirm');
3 const [feedback, setFeedback] = useState('');
4
5 const handleConfirm = () => {
6 setStep('feedback');
7 };
8
9 const handleSubmit = async () => {
10 // Submit feedback (optional)
11 if (feedback) {
12 await submitCancellationFeedback(subscription.id, feedback);
13 }
14
15 // Proceed with cancellation
16 await onCancel(subscription.id);
17 setStep('complete');
18 };
19
20 if (step === 'confirm') {
21 return (
22 <div>
23 <h3>Cancel {subscription.plan}?</h3>
24 <p>Your subscription will remain active until {subscription.nextBillingDate}</p>
25 <button onClick={handleConfirm}>Yes, Cancel</button>
26 <button onClick={() => window.history.back()}>Keep Subscription</button>
27 </div>
28 );
29 }
30
31 if (step === 'feedback') {
32 return (
33 <div>
34 <h3>Help us improve</h3>
35 <p>Why are you cancelling? (optional)</p>
36 <textarea
37 value={feedback}
38 onChange={(e) => setFeedback(e.target.value)}
39 placeholder="Your feedback..."
40 />
41 <button onClick={handleSubmit}>Complete Cancellation</button>
42 </div>
43 );
44 }
45
46 return (
47 <div>
48 <h3>Subscription Cancelled</h3>
49 <p>You'll have access until {subscription.nextBillingDate}</p>
50 <p>You can reactivate anytime from your account settings.</p>
51 </div>
52 );
53}

Reactivating Cancelled Subscriptions

Customers may want to reactivate a cancelled subscription. You’ll need to create a new subscription using the same plan code:

1// Create a new subscription with the same plan
2const response = await fetch(
3 'https://api-sandbox.coinflow.cash/api/subscription/{merchantId}/subscribers/card',
4 {
5 method: 'POST',
6 headers: {
7 'Content-Type': 'application/json',
8 'x-coinflow-auth-session-key': sessionKey
9 },
10 body: JSON.stringify({
11 planCode: previousPlanCode,
12 card: savedCardToken,
13 // ... other required fields
14 })
15 }
16);