Advanced integration
Learn how to embed a custom Stripe payment form in your website or application. The client- and server-side code builds a checkout form with Stripe’s Web or Mobile elements to let you accept payments. To build a custom integration that goes beyond the basics of this quickstart, see Accept a payment.
To learn about different payment scenarios, such as subscriptions, and other Stripe products, compare payment integrations.
Interested in using Stripe Tax, discounts, shipping, or currency conversion?
We’re developing a Payment Element integration that manages tax, discounts, shipping, and currency conversion. Read the Build a checkout page guide to learn more.
Install the Stripe Ruby library
Install the Stripe ruby gem and require it in your code. Alternatively, if you’re starting from scratch and need a Gemfile, download the project files using the link in the code editor.
Create a PaymentIntent
Add an endpoint on your server that creates a PaymentIntent. A PaymentIntent tracks the customer’s payment lifecycle, keeping track of any failed payment attempts and ensuring the customer is only charged once. Return the PaymentIntent’s client secret in the response to finish the payment on the client.
Configure payment methods
Stripe enables cards and other common payment methods by default with dynamic payment methods. You can update and configure payment methods from the Dashboard with no code required. Stripe filters payment methods based on eligibility and payment method preferences, then orders and displays them by probability based on factors including amount, currency, and buyer location.
Install the SDK
The Stripe Android SDK is open source and fully documented and compatible with devices running Android 5.0 (API level 21) and above.
To install the SDK, add stripe-android
to the dependencies block of your build.
file:
Note
For details on the latest SDK release and past versions, see the Releases page on GitHub.
Setup the SDK
Configure the Stripe SDK with your Stripe publishable API key. Hardcoding the publishable API key in the SDK is for demonstration only. In a production app, you must retrieve the API key from your server.
Fetch a PaymentIntent
Make a request to your server for a PaymentIntent as soon as the view loads. Store a reference to the PaymentIntent’s client secret returned by the server; the Payment Sheet uses this secret to complete the payment later.
Configure and present the Payment Sheet
Create a PaymentSheet
instance using the client secret retrieved earlier, and present it from your view controller.
Use the PaymentSheet.
struct for customizing the Payment Sheet.
Handle the payment result
Use the completion block for handling the payment result.
If payment fails with an error, display the appropriate message to your customer so they can take action and try again. If no error has occurred, tell your customer that the payment was successful.
Make a test payment
See your payment in the Dashboard
Navigate to the Stripe Dashboard to see your test payment.
Accept payments and enhance your integration
You’re ready to accept payments with Stripe. Continue with the steps below to add more features.
Calculate and collect the right amount of tax on your Stripe transactions. Before using Stripe Tax, you need to activate it in the Dashboard. Learn more about Stripe Tax and how to add it to your Payments integration.
Some payment methods can’t guarantee that you’ll receive funds from your customer at the end of the check out because they take time to settle (for example, most bank debits, such as SEPA or ACH) or require customer action to complete (for example, OXXO, Konbini, Boleto). Use this flag to enable delayed payment methods.
If you enable this feature, make sure your server integration listens to webhooks for notifications on whether payment has succeeded or not.
Card scanning can help increase your conversion rate by removing the friction of manual card entry. To enable card scanning, add stripecardscan
to the dependencies
block of your app/build.gradle file:
Often used by SaaS or e-commerce businesses with recurring customers.
Collect local and international shipping or billing addresses from your customers.
If you use the Address Element, you can optionally use the Google Places SDK to fetch address autocomplete suggestions. To enable autocomplete suggestions, add places
to the dependency block of your app/build.gradle file:
Next steps
Payouts
Learn how to move funds out of your Stripe account into your bank account.
Refunds
Handle requests for refunds by using the Stripe API or Dashboard.
Fulfillment
Create an event destination to send events to your webhook endpoint to fulfill orders after a payment succeeds, and to handle other critical events.
require 'sinatra'require 'stripe'# This is a public sample test API key.# Don’t submit any personally identifiable information in requests made with this key.# Sign in to see your own test API key embedded in code samples.Stripe.api_key = 'sk_test_BQokikJOvBiI2HlWgH4olfQ2'set :static, trueset :port, 4242# Securely calculate the order amountdef calculate_order_amount(_items)# Calculate the order total on the server to prevent# people from directly manipulating the amount on the client_items.sum {|h| h['amount']}end# An endpoint to start the payment processpost '/create-payment-intent' docontent_type 'application/json'data = JSON.parse(request.body.read)# Create a PaymentIntent with amount and currencypayment_intent = Stripe::PaymentIntent.create(amount: calculate_order_amount(data['items']),currency: 'usd',# In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default.automatic_payment_methods: {enabled: true,},){clientSecret: payment_intent.client_secret,}.to_jsonend
package com.example.demoimport android.app.Applicationimport com.stripe.android.PaymentConfigurationclass MyApp : Application() {override fun onCreate() {super.onCreate()PaymentConfiguration.init(applicationContext,"pk_test_TYooMQauvdEDq54NiTphI7jx")}}
package com.example.demoimport android.os.Bundleimport android.widget.Toastimport androidx.activity.compose.setContentimport androidx.appcompat.app.AppCompatActivityimport androidx.compose.foundation.layout.fillMaxWidthimport androidx.compose.material.AlertDialogimport androidx.compose.material.Buttonimport androidx.compose.material.Textimport androidx.compose.runtime.Composableimport androidx.compose.runtime.LaunchedEffectimport androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableStateOfimport androidx.compose.runtime.rememberimport androidx.compose.runtime.setValueimport androidx.compose.ui.Modifierimport androidx.compose.ui.graphics.Colorimport com.stripe.android.paymentsheet.PaymentSheetimport com.stripe.android.paymentsheet.PaymentSheetResultimport com.stripe.android.paymentsheet.rememberPaymentSheetimport okhttp3.*import okhttp3.MediaType.Companion.toMediaTypeimport okhttp3.RequestBody.Companion.toRequestBodyimport org.json.JSONExceptionimport org.json.JSONObjectimport java.io.IOExceptionimport kotlin.coroutines.resumeimport kotlin.coroutines.suspendCoroutineclass CheckoutActivity : AppCompatActivity() {companion object {private const val BACKEND_URL = "http://10.0.2.2:4242"}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {CheckoutScreen()}}@Composableprivate fun CheckoutScreen() {var paymentIntentClientSecret by remember { mutableStateOf<String?>(null) }var error by remember { mutableStateOf<String?>(null) }val paymentSheet = rememberPaymentSheet { paymentResult ->when (paymentResult) {is PaymentSheetResult.Completed -> showToast("Payment complete!")is PaymentSheetResult.Canceled -> showToast("Payment canceled!")is PaymentSheetResult.Failed -> {error = paymentResult.error.localizedMessage ?: paymentResult.error.message}}}error?.let { errorMessage ->ErrorAlert(errorMessage = errorMessage,onDismiss = {error = null})}LaunchedEffect(Unit) {fetchPaymentIntent().onSuccess { clientSecret ->paymentIntentClientSecret = clientSecret}.onFailure { paymentIntentError ->error = paymentIntentError.localizedMessage ?: paymentIntentError.message}}PayButton(enabled = paymentIntentClientSecret != null,onClick = {paymentIntentClientSecret?.let {onPayClicked(paymentSheet = paymentSheet,paymentIntentClientSecret = it,)}})}@Composableprivate fun PayButton(enabled: Boolean,onClick: () -> Unit) {Button(modifier = Modifier.fillMaxWidth(),enabled = enabled,onClick = onClick) {Text("Pay now")}}@Composableprivate fun ErrorAlert(errorMessage: String,onDismiss: () -> Unit) {AlertDialog(title = {Text(text = "Error occurred during checkout")},text = {Text(text = errorMessage)},onDismissRequest = onDismiss,confirmButton = {Button(onDismiss) {Text(text = "Ok")}})}private suspend fun fetchPaymentIntent(): Result<String> = suspendCoroutine { continuation ->val url = "$BACKEND_URL/create-payment-intent"val shoppingCartContent = """{"items": [{"id":"xl-tshirt"}]}"""val mediaType = "application/json; charset=utf-8".toMediaType()val body = shoppingCartContent.toRequestBody(mediaType)val request = Request.Builder().url(url).post(body).build()OkHttpClient().newCall(request).enqueue(object: Callback {override fun onFailure(call: Call, e: IOException) {continuation.resume(Result.failure(e))}override fun onResponse(call: Call, response: Response) {if (!response.isSuccessful) {continuation.resume(Result.failure(Exception(response.message)))} else {val clientSecret = extractClientSecretFromResponse(response)clientSecret?.let { secret ->continuation.resume(Result.success(secret))} ?: run {val error = Exception("Could not find payment intent client secret in response!")continuation.resume(Result.failure(error))}}}})}private fun extractClientSecretFromResponse(response: Response): String? {return try {val responseData = response.body?.string()val responseJson = responseData?.let { JSONObject(it) } ?: JSONObject()responseJson.getString("clientSecret")} catch (exception: JSONException) {null}}private fun showToast(message: String) {runOnUiThread {Toast.makeText(this, message, Toast.LENGTH_LONG).show()}}private fun onPayClicked(paymentSheet: PaymentSheet,paymentIntentClientSecret: String,) {val configuration = PaymentSheet.Configuration.Builder(merchantDisplayName = "Example, Inc.").build()// Present Payment SheetpaymentSheet.presentWithPaymentIntent(paymentIntentClientSecret, configuration)}}
source 'https://rubygems.org/'gem 'sinatra'gem 'stripe'
# Accept a PaymentBuild a simple checkout form to collect payment details. Included are some basicbuild and run scripts you can use to start up the application.## Running the sample1. Build the server~~~bundle install~~~2. Run the server~~~ruby server.rb -o 0.0.0.0~~~