How to Create Subscriptions in Paypal in Asp.Net Core
How to Create Subscriptions in Paypal in Asp.Net Core
In this article, we'll dive into integrating PayPal subscriptions into an ASP.NET Core application. PayPal offers a robust API that allows developers to create and manage subscription plans seamlessly. We'll walk through a sample code snippet that demonstrates how to create a subscription plan, add a product, and initiate a subscription for a user., we have to follow these steps :
First of all, take one Asp.net Core mvc application and we will install the PayPal Nuget package which is shown in the image below
After you have done installing the PayPal Nuget package we will have to take one new controller where we will add the PayPal integration code. You have to add these namespaces on the controller
using PayPal.Api;
So, now we have to add these methods in our controller, this method will help us initialize payment and redirect to the payment page
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using PayPal; using PayPal.Api; using PaypalCore.Models; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using System.Net.Http; using System.Text; using HttpResponse = Microsoft.AspNetCore.Http.HttpResponse; using HttpClient = System.Net.Http.HttpClient; using System.Numerics; using BraintreeHttp; namespace PaypalCore.Controllers { public class HomeController : Controller { private readonly ILogger<HomeController> _logger; private IHttpContextAccessor httpContextAccessor; IConfiguration _configuration; public HomeController(ILogger<HomeController> logger, IHttpContextAccessor context, IConfiguration iconfiguration) { _logger = logger; httpContextAccessor = context; _configuration = iconfiguration; } public IActionResult Index() { return View(); } public async Task<ActionResult> CreateSubscription() { var response = await CreateSubscriptionPlan("Silver Plan", "Monthly subscription", "MONTH", "REGULAR", 1, 12, "USD", "TIERED", "false", "ACTIVE"); string planId = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(response).id; return await AddSubscription(planId); } public async Task<string> CreateSubscriptionPlan(string name, string description, string billingCycleFrequency, string billingCycleTenureType, int billingCycleSequence, int billingCycleTotalCycles, string currencyCode, string pricingScheme, string quantitySupported, string status) { var productId = await CreateProduct("Test product", "Product for testing"); // Replace XXXXXXXXXXXX with your actual product ID var accessToken = await GetAccessToken(); string result = await CreatePlan(name, description, billingCycleFrequency, billingCycleTenureType, billingCycleSequence, billingCycleTotalCycles, currencyCode, quantitySupported, status, productId, accessToken); return result; } private static async Task<string> CreatePlan(string name, string description, string billingCycleFrequency, string billingCycleTenureType, int billingCycleSequence, int billingCycleTotalCycles, string currencyCode, string quantitySupported, string status, string productId, string accessToken) { var client = new System.Net.Http.HttpClient(); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); var requestUrl = "https://api.sandbox.paypal.com/v1/billing/plans"; var requestData = new { product_id = productId, name, description, billing_cycles = new[] { new { frequency = new { interval_unit = billingCycleFrequency, interval_count = 1 }, tenure_type = billingCycleTenureType, sequence = billingCycleSequence, total_cycles = billingCycleTotalCycles, pricing_scheme = new { fixed_price = new { value = "10", currency_code = currencyCode } } } }, payment_preferences = new { auto_bill_outstanding = true, setup_fee = new { currency_code = currencyCode, value = "0" }, setup_fee_failure_action = "CONTINUE", payment_failure_threshold = 3 }, taxes = new { percentage = "0", inclusive = false }, quantity_supported = quantitySupported, status }; var requestDataJson = Newtonsoft.Json.JsonConvert.SerializeObject(requestData); var requestContent = new StringContent(requestDataJson, Encoding.UTF8, "application/json"); var response = await client.PostAsync(requestUrl, requestContent); var result = response.Content.ReadAsStringAsync().Result; return result; } public async Task<string> CreateProduct(string name, string description) { var accessToken = await GetAccessToken(); var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); var requestUrl = "https://api.sandbox.paypal.com/v1/catalogs/products"; var requestData = new { name, description }; var requestDataJson = Newtonsoft.Json.JsonConvert.SerializeObject(requestData); var requestContent = new StringContent(requestDataJson, Encoding.UTF8, "application/json"); var response = await client.PostAsync(requestUrl, requestContent); var responseContent = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { var productId = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responseContent).id; return productId; } else { throw new Exception($"Failed to create product. {responseContent}"); } } public async Task<ActionResult> AddSubscription(string planId) { var _httpClient = new HttpClient(); string url = "https://api.sandbox.paypal.com/v1/billing/subscriptions"; string accessToken = await GetAccessToken(); // Replace with your actual access token var requestData = new { plan_id = planId, start_time = DateTime.Now.AddDays(2), shipping_amount = new { currency_code = "USD", value = "10.00" }, subscriber = new { name = new { given_name = "John", surname = "Doe" }, email_address = "shubhsaini777@gmail.com", shipping_address = new { name = new { full_name = "John Doe" }, address = new { address_line_1 = "2211 N First Street", address_line_2 = "Building 17", admin_area_2 = "San Jose", admin_area_1 = "CA", postal_code = "95131", country_code = "US" } } }, application_context = new { brand_name = "Code2night", locale = "en-US", shipping_preference = "SET_PROVIDED_ADDRESS", user_action = "SUBSCRIBE_NOW", return_url = "https://localhost:44357/Success", cancel_url = "https://localhost:44357/cancel" } }; var requestContent = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json"); _httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); var response = await _httpClient.PostAsync(url, requestContent); var responseContent = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { dynamic response1 = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responseContent); // Extract the approve URL from the links in the response string approveUrl = response1.links[0].href; // Redirect the user to the approve URL for manual approval return new RedirectResult(approveUrl); // return Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responseContent).id; } else { throw new Exception($"Failed to create subscription: {responseContent}"); } } private async Task<string> GetAccessToken() { var ClientID = _configuration.GetValue<string>("PayPal:Key"); var ClientSecret = _configuration.GetValue<string>("PayPal:Secret"); var mode = _configuration.GetValue<string>("PayPal:mode"); var client = new HttpClient(); var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{ClientID}:{ClientSecret}")); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", credentials); var requestUrl = "https://api.sandbox.paypal.com/v1/oauth2/token"; var requestData = new StringContent("grant_type=client_credentials", Encoding.UTF8, "application/x-www-form-urlencoded"); var response = await client.PostAsync(requestUrl, requestData); var responseContent = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { var accessToken = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responseContent).access_token; return accessToken; } else { throw new Exception($"Failed to get access token. {responseContent}"); } } [HttpGet("success")] public IActionResult SubscriptionSuccess(string subscription_id) { // Handle successful subscription completion return Ok("Subscription successful!"); } [HttpGet("cancel")] public IActionResult SubscriptionCancel() { // Handle subscription cancellation return Ok("Subscription cancelled!"); } } }
After this now you have to go to the model's folder and add a new class file PaypalConfiguration.cs . And add the following code there
public static class PaypalConfiguration { //Variables for storing the clientID and clientSecret key //Constructor static PaypalConfiguration() { } // getting properties from the web.config public static Dictionary<string, string> GetConfig(string mode) { return new Dictionary<string, string>() { {"mode",mode} }; } private static string GetAccessToken(string ClientId, string ClientSecret, string mode) { // getting accesstocken from paypal string accessToken = new OAuthTokenCredential(ClientId, ClientSecret, new Dictionary<string, string>() { {"mode",mode} }).GetAccessToken(); return accessToken; } public static APIContext GetAPIContext(string clientId, string clientSecret, string mode) { // return apicontext object by invoking it with the accesstoken APIContext apiContext = new APIContext(GetAccessToken(clientId, clientSecret, mode)); apiContext.Config = GetConfig(mode); return apiContext; } }
Understanding the Code
Let's break down the provided code snippet step by step:
CreateSubscription Method
This method initiates the process of creating a subscription by calling the CreateSubscriptionPlan
method to create a subscription plan and then invoking the AddSubscription
method to add a subscription.
public async Task<ActionResult> CreateSubscription()
{
var response = await CreateSubscriptionPlan("Silver Plan", "Monthly subscription", "MONTH", "REGULAR", 1, 12, "USD", "TIERED", "false", "ACTIVE");
string planId = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(response).id;
return await AddSubscription(planId);
}
CreateSubscriptionPlan Method
This method is responsible for creating a subscription plan. It first calls the CreateProduct
method to create a product, retrieves an access token, and then makes an API call to PayPal to create the plan.
public async Task<string> CreateSubscriptionPlan(string name, string description, string billingCycleFrequency, string billingCycleTenureType, int billingCycleSequence, int billingCycleTotalCycles, string currencyCode, string pricingScheme, string quantitySupported, string status)
{
var productId = await CreateProduct("Test product", "Product for testing");
var accessToken = await GetAccessToken();
string result = await CreatePlan(name, description, billingCycleFrequency, billingCycleTenureType, billingCycleSequence, billingCycleTotalCycles, currencyCode, quantitySupported, status, productId, accessToken);
return result;
}
CreatePlan Method
This method constructs the request payload and sends a POST request to PayPal's API to create a subscription plan. You need this if you haven't already created a subscription plan from UI. However, the plans created from UI doesn't work with sandbox credentials.
private static async Task<string> CreatePlan(string name, string description, string billingCycleFrequency, string billingCycleTenureType, int billingCycleSequence, int billingCycleTotalCycles, string currencyCode, string quantitySupported, string status, string productId, string accessToken)
{
var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var requestUrl = "https://api.sandbox.paypal.com/v1/billing/plans";
var requestData = new
{
product_id = productId,
name,
description,
billing_cycles = new[]
{
new
{
frequency = new
{
interval_unit = billingCycleFrequency,
interval_count = 1
},
tenure_type = billingCycleTenureType,
sequence = billingCycleSequence,
total_cycles = billingCycleTotalCycles,
pricing_scheme = new
{
fixed_price = new
{
value = "10",
currency_code = currencyCode
}
}
}
},
payment_preferences = new
{
auto_bill_outstanding = true,
setup_fee = new
{
currency_code = currencyCode,
value = "0"
},
setup_fee_failure_action = "CONTINUE",
payment_failure_threshold = 3
},
taxes = new
{
percentage = "0",
inclusive = false
},
quantity_supported = quantitySupported,
status
};
var requestDataJson = Newtonsoft.Json.JsonConvert.SerializeObject(requestData);
var requestContent = new StringContent(requestDataJson, Encoding.UTF8, "application/json");
var response = await client.PostAsync(requestUrl, requestContent);
var result = response.Content.ReadAsStringAsync().Result;
return result;
}
AddSubscription Method
This method adds a subscription by sending a POST request to PayPal's API. This method is basically the final steps for buying the subscription . After this it will redirect to checkout screen for the subscription payment.
public async Task<ActionResult> AddSubscription(string planId)
{
var _httpClient = new HttpClient();
string url = "https://api.sandbox.paypal.com/v1/billing/subscriptions";
string accessToken = await GetAccessToken();
var requestData = new
{
plan_id = planId,
start_time = DateTime.Now.AddDays(2),
shipping_amount = new
{
currency_code = "USD",
value = "10.00"
},
subscriber = new
{
name = new
{
given_name = "John",
surname = "Doe"
},
email_address = "shubhsaini777@gmail.com",
shipping_address = new
{
name = new
{
full_name = "John Doe"
},
address = new
{
address_line_1 = "2211 N First Street",
address_line_2 = "Building 17",
admin_area_2 = "San Jose",
admin_area_1 = "CA",
postal_code = "95131",
country_code = "US"
}
}
},
application_context = new
{
brand_name = "Code2night",
locale = "en-US",
shipping_preference = "SET_PROVIDED_ADDRESS",
user_action = "SUBSCRIBE_NOW",
return_url = "https://localhost:44357/Success",
cancel_url = "https://localhost:44357/cancel"
}
};
var requestContent = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(requestData), Encoding.UTF8, "application/json");
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var response = await _httpClient.PostAsync(url, requestContent);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
dynamic response1 = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responseContent);
string approveUrl = response1.links[0].href;
return new RedirectResult(approveUrl);
}
else
{
throw new Exception($"Failed to create subscription: {responseContent}");
}
}
CreateProduct Method
This method creates a product using PayPal's API. We need product for creating a subscription plan.
public async Task<string> CreateProduct(string name, string description)
{
var accessToken = await GetAccessToken();
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var requestUrl = "https://api.sandbox.paypal.com/v1/catalogs/products";
var requestData = new
{
name,
description
};
var requestDataJson = Newtonsoft.Json.JsonConvert.SerializeObject(requestData);
var requestContent = new StringContent(requestDataJson, Encoding.UTF8, "application/json");
var response = await client.PostAsync(requestUrl, requestContent);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var productId = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responseContent).id;
return productId;
}
else
{
throw new Exception($"Failed to create product. {responseContent}");
}
}
GetAccessToken Method
This method retrieves an access token required for making requests to PayPal's API.
private async Task<string> GetAccessToken()
{
var ClientID = _configuration.GetValue<string>("PayPal:Key");
var ClientSecret = _configuration.GetValue<string>("PayPal:Secret");
var mode = _configuration.GetValue<string>("PayPal:mode");
var client = new HttpClient();
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{ClientID}:{ClientSecret}"));
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", credentials);
var requestUrl = "https://api.sandbox.paypal.com/v1/oauth2/token";
var requestData = new StringContent("grant_type=client_credentials", Encoding.UTF8, "application/x-www-form-urlencoded");
var response = await client.PostAsync(requestUrl, requestData);
var responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var accessToken = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responseContent).access_token;
return accessToken;
}
else
{
throw new Exception($"Failed to get access token. {responseContent}");
}
}
Now go to your web config file and add two app settings for client id and client secret
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "PayPal": { "Key": "AfIlrsSZigDDFLni0K2VIUrfLObfNvqtCT2mcBvNUxgLTxPUs_o21gVTjoggSpYFcF2hqkMhfVUSqCv1w", "Secret": "ECeznQaEnGGSzbtF1mNvyZPSUIrZxfsA-XJlZgrDwjJSI1hj1lqT5r1nISJLYeR2xwBarEg5Mq4n18Lm7", "mode": "sandbox" } }
Here, please replace the credentials with your original credentials.
Now add one view and add the following code there for the payment button
<div class="jumbotron"> <h1>Paypal Subscriptions in Asp.Net Core</h1> </div> <div class="row"> <a class="btn btn-primary" href="/Home/CreateSubscription">Buy Subscription</a> </div>
Now, we have to run the application and you will see this
Click on the button and it will call Action PaymentWithPaypal on HomeController. Now, it will create one default item and redirect to the payment page as shown below
Now click on the Pay with credit or debit card button and it will redirect to a screen where you will have to add card details.
You can fill in the following details here for sandbox testing
Country - United States Card Type: Visa Card Number: 4032034155351326 Expiration Date: 09/24 CVV: 275 Street: 4790 Deer Haven Drive City: Greenville State/province/area: South Carolina Phone number 864-353-5437 Zip code 29601 Country calling code +1
Now click on Agree & subscribe
and it will hit back the same method Here, you can add a breakpoint and check if your subscription is created and you have received the subscription Id.
For, the production environment you can use
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "PayPal": { "Key": "AfIlrsSZigDDFLni0K2VIUrfLObfNvqtCT2mcBvNUxgLTxPUs_o21gVTjoggSpYFcF2hqkMhfVUSqCv1w", "Secret": "ECeznQaEnGGSzbtF1mNvyZPSUIrZxfsA-XJlZgrDwjJSI1hj1lqT5r1nISJLYeR2xwBarEg5Mq4n18Lm7", "mode": "live" //For production } }
So after changing the mode you just have to set live credentials in web.config and you will be able to use this on production.
This is how to Create Subscriptions in Paypal in Asp.Net Core.