Want to get ahead in your business by offering personalized payment and subscription options that fit your customer’s specific needs? Stripe can make this easier with an SDK that lets you easily create complex pricing plans. In this post, I delve into how you can streamline your Stripe integration with Kotlin.

Table of Contents

Custom Checkout

Stripe Checkout supports custom payment flows, allowing developers to tailor the customer experience according to their business needs. Below is an example code from Stripe’s documentation. It creates a custom Checkout Session for a purchased item.

import com.stripe.model.checkout.Session

Stripe.apiKey = "sk_test_your_key";

List<Object> lineItems = new ArrayList<>();
Map<String, Object> lineItem1 = new HashMap<>();
lineItem1.put("price", "price_H5ggYwtDq4fbrJ");
lineItem1.put("quantity", 2);
lineItems.add(lineItem1);
Map<String, Object> params = new HashMap<>();
params.put(
  "success_url",
  "https://example.com/success"
);
params.put("line_items", lineItems);
params.put("mode", "payment");

Session session = Session.create(params);

// Use the session URL to redirect your customer to the Stripe's checkout page
session.url

The example creates a checkout session in Stripe. Subsequently, you can use the session’s link, session.url, to redirect your customer to a Stripe’s checkout page. Moving on, the method types specify how the customer can pay, such as using a credit card. Additionally, the line items are the products or services being sold. Furthermore, depending upon the success or cancellation of the payment, you redirect the customer either to a success or a cancellation endpoint.

As much as this code excerpt makes for a great documentation of how the feature should be used, making it usable requires a bit of extra work.

Checkout Session Builder In Kotlin

First of all, in real-life project the list of purchased items varies. Let’s assume that we need a component that allows us to build an arbitrary list of items and submit them all of them at once in a single transaction. A Builder pattern seems to be good fit here.

Switching from Java to Kotlin, the implementation of a checkout session builder looks as follows.

package com.tomaszezula.stripe101.examples.payments

import com.stripe.model.checkout.Session

typealias LineItem = Map<String, Any>

class CheckoutSessionBuilder {
    private var lineItems: List<LineItem> = mutableListOf()

    fun addLineItem(priceId: String, quantity: Long): CheckoutSessionBuilder {
        val lineItem = mapOf(
            "price" to priceId,
            "quantity" to quantity
        )
        lineItems += lineItem
        return this
    }

    fun build(successUrl: String, cancelUrl: String): Session {
        return Session.create(
            mapOf(
                "payment_method_types" to listOf("card"),
                "line_items" to lineItems,
                "mode" to "subscription",
                "success_url" to successUrl,
                "cancel_url" to cancelUrl
            )
        )
    }
}

Here is how we would use it.

fun main() {
    Stripe.apiKey = "your api key"

    val builder = CheckoutSessionBuilder()
    val session = builder
        .addLineItem(priceId = "price_1NtOfQGyWpmEflR8il6mXoFE", quantity = 1)
        .addLineItem(priceId = "price_1NtOj5GyWpmEflR8UyQMt48n", quantity = 5)
        .build(
            successUrl = "https://example.com/success",
            cancelUrl = "https://example.com/cancel"
        )
    println(session.url)
}

Visiting the session’s link leads to a custom checkout page.

I am about to purchase a monthly subscription along with five branded mugs for my team mates.

Subscription Tiers

Subscription tiers refer to different pricing levels within a subscription plan. They enable customers to choose a package that suits their needs or budget. The tier is represented by a Price object constructed identically to the checkout session. If there is one thing I love about Stripe, it’s the uniformity of their API.

Now, let’s explore an example of creating a subscription with a tiered pricing plan in Kotlin.

package com.tomaszezula.stripe101.examples.payments

import com.stripe.Stripe
import com.stripe.model.Price

typealias PriceTier = Map<String, Any>

class TieredPriceBuilder {
    private var priceTiers: List<PriceTier> = mutableListOf()

    fun addPriceTier(quantity: Long? = null, unitAmount: Long): TieredPriceBuilder {
        val priceTier = mapOf(
            "up_to" to (quantity ?: "inf"),
            "unit_amount" to unitAmount
        )
        priceTiers += priceTier
        return this
    }

    fun build(currency: String, productId: String, tiersMode: String): Price {
        return Price.create(
            mapOf(
                "currency" to currency,
                "product" to productId,
                "tiers_mode" to tiersMode,
                "tiers" to priceTiers,
                "recurring" to mapOf(
                    "interval" to "month",
                    "interval_count" to 1
                ),
                "billing_scheme" to "tiered"
            )
        )
    }
}

Usage:

fun main() {
    Stripe.apiKey = "your api key"

    val builder = TieredPriceBuilder()
    val price = builder
        .addPriceTier(quantity = 5, unitAmount = 1000)
        .addPriceTier(unitAmount = 750)
        .build(
            currency = "usd",
            productId = "prod_OgmmKvjqDCDvcM",
            tiersMode = "graduated"
        )
    println(price)
}

Here, we create two price tiers, each with unique characteristics. The first tier provides up to 10 units at a unit price of $10.00, while the second tier provides an unlimited number of units at reduced unit costs of $7.50.

Now I can purchase the product at a discounted price.

Purchasing more than 5 seats leads to a discounted unit price of $7.50 per seat per month.

Summary

Through these examples, you get a taste of the flexibility and power Stripe provides developers with its robust, feature-packed Java SDK. With the help of Stripe’s checkout sessions and subscription tiers, developers can create complex custom payment structures catering to the evolving needs of their customers. The transition from Java to Kotlin is not only instinctive but also offers the added benefit of a more concise and manageable code.

Thanks for reading. Feel free to explore the code examples on GitHub.


Tomas Zezula

Hello! I'm a technology enthusiast with a knack for solving problems and a passion for making complex concepts accessible. My journey spans across software development, project management, and technical writing. I specialise in transforming rough sketches of ideas to fully launched products, all the while breaking down complex processes into understandable language. I believe a well-designed software development process is key to driving business growth. My focus as a leader and technical writer aims to bridge the tech-business divide, ensuring that intricate concepts are available and understandable to all. As a consultant, I'm eager to bring my versatile skills and extensive experience to help businesses navigate their software integration needs. Whether you're seeking bespoke software solutions, well-coordinated product launches, or easily digestible tech content, I'm here to make it happen. Ready to turn your vision into reality? Let's connect and explore the possibilities together.