When a customer on a trial wants to upgrade to a paid plan, you can run the upgrade through Chargebee Checkout. Checkout is PCI DSS compliant, so sensitive card information never reaches your servers.
Honey Comics is a fictitious online comic book store that sends comic books to its subscribers every week. It offers a one-month free trial, and customers can upgrade to a paid plan on the website. They are charged immediately on upgrade. Try the demo, then follow the steps below to build something similar.
To keep the sample code short, it uses no database and has no real login, so the user ID is hard-coded.
Prerequisites
- Sign up for a Chargebee account.
- Create a plan with a trial period on your Chargebee test site.
- Get the API key for your Chargebee test site.
Build the upgrade page
Build a page where customers can upgrade. Clicking the upgrade button opens Chargebee Checkout.
Set up the client library
Download and import the client library for your language, then configure it with your Chargebee test site name and API key.
ChargeBee.configure(:site => "honeycomics-v3-test",
:api_key => "<full-access-key>")
const chargebee = new Chargebee({
site : "honeycomics-v3-test",
apiKey : "<full-access-key>",
});
Environment.configure("honeycomics-v3-test","<full-access-key>");
import chargebee
chargebee.configure("<full-access-key>", "honeycomics-v3-test")
/*
* Sets the environment for calling the Chargebee API.
* You need to sign up at Chargebee app to get this credential.
* It is better if you fetch configuration from the environment
* properties instead of hard coding it in code.
*/
ChargeBee_Environment::configure("honeycomics-v3-test",
"<full-access-key>");
Add an endpoint that returns a hosted page object
On your server, call the checkout existing subscription API with the trial subscription ID. It returns a hosted page object for the upgrade.
def checkout_existing
# Subscription id must match the trial subscription which you have created for the currently logged-in user
subscription_id = "cbdemo_sir-sub"
result = ChargeBee::HostedPage.checkout_existing({
:subscription => {:id => subscription_id },
:embed => false
})
render :json => result.hosted_page.to_s
end
app.post("/api/generate_checkout_existing_url", (req, res) => {
chargebee.hosted_page.checkout_existing({
subscription : {
id : "cbdemo_sir-sub"
},
}).request(function(error,result){
if(error){
//handle error
console.log(error);
}else{
res.send(result.hosted_page);
}
});
});
@WebServlet(name = "checkout_existing", value = {"generate_checkout_existing_url"})
public class CheckoutExisting extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException {
String subscriptionId = "cbdemo_sir-sub";
Result result = null;
try {
result = HostedPage.checkoutExisting()
.subscriptionId(subscriptionId).request(new Environment("honeycomics-v3-test", "<full-access-key>"));
} catch (Exception e) {
e.printStackTrace();
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setContentType("application/json");
response.getWriter().print("{\"error\":\"Failed to create hosted page\"}");
return;
}
HostedPage hostedPage = result.hostedPage();
// Dont add the below header in production. This is only for demo
response.addHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json");
response.getWriter().print(hostedPage.jsonObj);
}
}
@app.route('/api/generate_checkout_existing_url', methods=['POST'])
def generate_checkout_existing_url():
result = chargebee.HostedPage.checkout_existing({
"subscription" : {
"id" : "cbdemo_sir-sub"
}
})
hosted_page = result._response['hosted_page']
return jsonify(hosted_page)
public function generateCheckoutExistingUrl(Request $request) {
$result = ChargeBee_HostedPage::checkoutExisting(array(
"subscription" => array(
"id" => "cbdemo_sir-sub"
)
));
$hostedPage = $result->hostedPage();
return response()->json($hostedPage->getValues(), 200);
}
To use PayPal, GoCardless, or Plaid, pass embed as false when you create the hosted page.
Open Checkout on click
On the client, openCheckout takes a hostedPage callback that returns a promise. Make it call the endpoint you created above and resolve to the hosted page object.
$("#upgrade").on("click", function(event) {
event.preventDefault();
cbInstance.openCheckout({
hostedPage: function() {
// Hit your end point that returns hosted page JSON object as response
return $.ajax({
method: "post",
url: "http://localhost:8000/api/generate_checkout_existing_url"
});
},
loaded: function() {
console.log("checkout opened");
},
error: function() {
},
close: function() {
console.log("checkout closed");
},
success: function(hostedPageId) {
console.log(hostedPageId);
// Hosted page id will be unique token for the checkout that happened
// You can pass this hosted page id to your backend
// and then call our retrieve hosted page api to get subscription details
// https://apidocs.chargebee.com/docs/api/hosted_pages/retrieve-a-hosted-page
},
step: function(value) {
// value -> which step in checkout
console.log(value);
}
});
});
this.cbInstance.openCheckout({
hostedPage: () => {
// Hit your end point that returns hosted page JSON object as response
return axios.post("http://localhost:8000/api/generate_checkout_existing_url", urlEncode({plan_id: "cbdemo_scale"})).then((response) => response.data)
},
loaded: function() {
console.log("checkout opened");
},
close: function() {
console.log("checkout closed");
},
success: function(hostedPageId) {
console.log(hostedPageId);
},
step: function(value) {
// value -> which step in checkout
console.log(value);
}
});
this.cbInstance.openCheckout({
hostedPage: () => {
// Hit your end point that returns hosted page JSON object as response
return this.http.post("http://localhost:8000/api/generate_checkout_existing_url", {}, {headers: new HttpHeaders({'Content-Type': 'application/x-www-form-urlencoded'})}).toPromise();
},
loaded: () => {
console.log("checkout opened");
},
close: () => {
console.log("checkout closed");
},
success: (hostedPageId) => {
console.log(hostedPageId);
},
step: (value) => {
// value -> which step in checkout
console.log(value);
}
});
this.state.cbInstance.openCheckout({
hostedPage: () => {
// Hit your end point that returns hosted page JSON object as response
return axios.post("http://localhost:8000/api/generate_checkout_existing_url", urlEncode({})).then((response) => response.data)
},
success(hostedPageId) {
console.log(hostedPageId);
},
close:() => {
this.setState({loading: false});
console.log("checkout new closed");
},
step(step) {
console.log("checkout", step);
}
});
The success callback receives a hosted page ID, a unique token for that checkout. Pass it to your backend and call the retrieve a hosted page API to get the subscription details.
Reference
For every openCheckout option and callback, see the Chargebee instance reference in the Chargebee.js Reference.
To create a new subscription instead of upgrading an existing one, see Create a new subscription with Chargebee Checkout.
We're always happy to help you with any questions you might have! Click here to reach out to us.