Skip to main content

iOS SDK for Apple Pay payments

· 11 min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Introduction

This document provides knowledge in building the iOS app that accepts payment in iOS devices, with built-in support for Apple Pay.

If you want to build a mobile app like Lyft and enable people to make purchases directly in your app, our iOS libraries can help. The library also supports Apple Pay so that your users can make frictionless payments without having to enter in their credit card info.

Accepting payments in your app involves 3 steps:

  1. Collecting credit card information from your customer
  2. Converting the credit card information to a single-use token
  3. Sending this token to your server to create a charge

Getting started

Install the library

Using CocoaPods

We recommend using CocoaPods to install the Stripe iOS library since it makes it easy to keep your app’s dependencies up-to-date.

If you have not set up CocoaPods before, we recommend following the installation instructions on the CocoaPods site, then add pod ‘Stripe’ to your Podfile, and run pod install.

Note:
Use the .xcworkspace file to open your project in Xcode instead of the .xcodeproj file.

Using Carthage

To use Carthage, simply add github “stripe/stripe-ios” to your Cartfile and follow the Carthage Installation instructions.

Using manual installation

We publish our SDK as a static framework that you can copy directly into your app without any additional tools. To manually install the library, do the following:

  1. Head to our releases page and downloads the framework that is right for you.
  2. Unzip the file you downloaded.
  3. In Xcode, with your project open, click File > Add files.
  4. Select Stripe.framework in the directory you just unzipped.
  5. Make sure Copy items if needed is checked.
  6. Click Add.
  7. In your project settings, go to the Build Settings tab, and under Other Linker Flags, make sure -ObjC is present.

Configure API keys

First, configure Stripe with your published API key. We recommend doing this in your AppDelegate’s application:didFinishLaunchingWithOptions method so that it will be set for the entire lifecycle of your app.

Example in Swift

// AppDelegate.swift

import Stripe

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?)
-> Bool {
Stripe.setDefaultPublishableKey("pk_test_6pRNASCoBOKtIshFeQd4XMUh")
return true
}
}

Example in Objective-C

// AppDelegate.m

#import "AppDelegate.h"
#import <Stripe/Stripe.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[Stripe setDefaultPublishableKey:@"pk_test_6pRNASCoBOKtIshFeQd4XMUh"];
return YES;
}

@end

Note:
We have placed your test publishable API key as the StripePublishableKey constant in the above snippet. You will need to swap it out with your live publishable key in production. You can see all your API keys in your dashboard.

Collecting credit card information

There are three ways to obtain payment details from the user:

  1. Use the Apple Pay framework to access your users’ stored payment information.
  2. Use our pre-built form component, STPPaymentCardTextField to collect new credit card details.
  3. Build your own credit card form from scratch.

Since Apple Pay supports only certain credit cards on the latest iOS devices, we recommend using Apple Pay in combination with option 2 or option 3 as a fallback on devices where Apple Pay is not available.

Using Apple Pay

With Apple Pay, you are able to access payment information stored on your customer’ iOS devices.

Important note before starting To use Apple Pay, you need to add the Apple Pay capability to your app in Xcode. This requires creating a merchant ID with Apple first, as explained in the “Getting Started with Apple Pay” documentation.

After setting up the merchant ID, you need to generate a PKPaymentRequest to submit to Apple. We have provided a convenient method to generate one with reasonable defaults. All you need to do is set the paymentSummaryItems property to an array of PKPaymentSummaryItems . These are analogous to line items on a receipt and are used to explain your charge to the user. For more details, see the PKPaymentRequest documentation.

Now that you have created the request, the next step is to query the device to see if Apple Pay is available; that is, if your app is running on the latest hardware and the user has added a valid credit card. YOUR_APPLE_MERCHANT_ID is an identifier that you obtain directly from Apple. If Apple Pay is available, you should create and display the payment request view controller. To do so, follow the below code:

Example in Swift

// ViewController.swift

guard let request = Stripe.paymentRequestWithMerchantIdentifier("YOUR_APPLE_MERCHANT_ID") else {
// request will be nil if running on < iOS8
return
}
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Premium Llama Food", amount: 10.0)
]

if (Stripe.canSubmitPaymentRequest(request)) {
let paymentController = PKPaymentAuthorizationViewController(paymentRequest: request)
presentViewController(paymentController, animated: true, completion: nil)
} else {
// Show the user your own credit card form (see options 2 or 3)

}

Example in Objective-C

// ViewController.m

PKPaymentRequest *request = [Stripe paymentRequestWithMerchantIdentifier:"YOUR_APPLE_MERCHANT_ID"];
NSString *label = @"Premium Llama Food";
NSDecimalNumber *amount = [NSDecimalNumber decimalNumberWithString:@"10.00"];
request.paymentSummaryItems = @[
[PKPaymentSummaryItem summaryItemWithLabel:label
amount:amount]
];

if ([Stripe canSubmitPaymentRequest:request]) {
PKPaymentAuthorizationViewController *paymentController;
paymentController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:paymentRequest];
paymentController.delegate = self;
[self presentViewController:paymentController animated:YES completion:nil];

} else {
// Show the user your own credit card form (see options 2 or 3)
}

Note that ViewController is a PKPaymentAuthorizationViewControllerDelegate. By implementing this protocol, the PKPayment is handled to return the authorization controller.

Example in Swift

// ViewController.swift

func paymentAuthorizationViewController(controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment:
PKPayment, completion: (PKPaymentAuthorizationStatus) -> Void) {
/*
We'll implement this method below in 'Creating a single-use token'.
Note that we've also been given a block that takes a PKPaymentAuthorizationStatus.
We'll call this function with either PKPaymentAuthorizationStatusSuccess or PKPaymentAuthorizationStatusFailure
after all of our asynchronous code is finished executing.
This is how the PKPaymentAuthorizationViewController knows when and how to update its UI.
*/
handlePaymentAuthorizationWithPayment(payment, completi
on: nil)
}

func paymentAuthorizationViewControllerDidFinish(controller: PKPaymentAuthorizationViewController) {
dismissViewControllerAnimated(true, completion: nil)
}

Example in Objective-C

// ViewController.m

- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didAuthorizePayment:(PKPayment *)payment
completion:(void (^)(PKPaymentAuthorizationStatus))completion {
/*
We'll implement this method below in 'Creating a single-use token'.
Note that we've also been given a block that takes a PKPaymentAuthorizationStatus.
We'll call this function with either PKPaymentAuthorizationStatusSuccess or PKPaymentAuthorizationStatusFailure
after all of our asynchronous code is finished executing.
This is how the PKPaymentAuthorizationViewController knows when and how to update its UI.
*/
[self handlePaymentAuthorizationWithPayment:payment completion:completion];
}

- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller {
[self dismissViewControllerAnimated:YES completion:nil]
;
}

To implement optional PKPaymentAuthorizationViewControllerDelegate methods for customer events (such as, to recalculate shipping costs based on user selection, see the PKPaymentAuthorizationViewController documentation.

Important:
Before doing the next step, make sure the controller has returned with a PKPayment.

Using STPPPaymentCardTextField

To use our pre-built form component, you need to create a view controller called PaymentViewController and add an STPPaymentCardTextField property to it.

Example in Swift

// PaymentViewController.swift

class PaymentViewController: UIViewController, STPPaymentCardTextFieldDelegate {
let paymentTextField = STPPaymentCardTextField()
}

Example in Objective-C
// PaymentViewController.m

#import "PaymentViewController.h"

@interface PaymentViewController ()<STPPaymentCardTextField Delegate>
@property(nonatomic) STPPaymentCardTextField *paymentTextField;
@end

To instantiate the STPPaymentCardTextField, set the PaymentViewController as its STPPaymentCardTextFieldDelegate and add it to your view.

Example in Swift

// PaymentViewController.swift

override func viewDidLoad() {
super.viewDidLoad();
paymentTextField.frame = CGRectMake(15, 15, CGRectGetWidth(self.view.frame) - 30, 44)
paymentTextField.delegate = self
view.addSubview(paymentTextField)
}

Example in Objective-C

// PaymentViewController.m

- (void)viewDidLoad {
[super viewDidLoad];
self.paymentTextField = [[STPPaymentCardTextField alloc] initWithFrame:CGRectMake(15, 15, CGRectGetWidth(self.view.frame) - 30, 44)];
self.paymentTextField.delegate = self;
[self.view addSubview:self.paymentTextField];
}

By adding an STPPaymentCardTextField to the controller, your app is enabled to accept card numbers, expiration dates, and CVCs. It will also format the input and validate that input on-the-fly.

When a user enters text into this field, the paymentCardTextFieldidChange method will be called on our view controller. In this callback, we can enable a save button to allow users to submit their valid cards if the form is valid.

Example in Swift

func paymentCardTextFieldDidChange(textField: STPPaymentCardTextField) {
// Toggle navigation, for example
saveButton.enabled = textField.isValid
}

Example in Objective-C

- (void)paymentCardTextFieldDidChange:(STPPaymentCardTextField *)textField { {
// Toggle navigation, for example
self.saveButton.enabled = textField.isValid;
}

Building your own form

To build your own form, make sure you will at least be able to collect your customer’s card numbers and expiration dates. We recommend you to also collect the CVC to prevent fraudulent. The user’s name and billing address are optional and would benefit you in terms of fraud protection.

Creating tokens

Our libraries shoulder the burden of PCI compliance by helping you avoid the need to send card data directly to your server. Instead, our libraries send credit card directly to our servers where we can then convert them to tokens. You can charge these tokens later in your server-side code.

Using PKPayment (Apple Pay)

After your PKPayment has arrived, you can turn it into a single-use Stripe token with a simple method call by using the following code.

Example in Swift

// ViewController.swift

func handlePaymentAuthorizationWithPayment(payment: PKPayment, completion: PKPaymentAuthorizationStatus -> ()) {
STPAPIClient.sharedClient().createTokenWithPayment(payment) { (token, error) -> Void in
if error != nil {
completion(PKPaymentAuthorizationStatus.Failure)
return
}
/*
We'll implement this below in "Sending the token to your server".
Notice that we're passing the completion block through.
See the above comment in didAuthorizePayment to learn why.
*/
createBackendChargeWithToken(token, completion: completion)
}
}

Example in Objective-C

// ViewController.m

- (void)handlePaymentAuthorizationWithPayment:(PKPayment *) payment
completion:(void (^)(PKPaymentAuthorizationStatus))completion {
[[STPAPIClient sharedClient] createTokenWithPayment:payment
completion:^(STPToken *token, NSError *error) {
if (error) {
completion(PKPaymentAuthorizationStatus Failure);
return;
}
/*
We'll implement this below in "Sending the token to your server".
Notice that we're passing the completion block through.
See the above comment in didAuthorizePayment to learn why.
*/
[self createBackendChargeWithToken:token completion:completion];
}];
}

Using STPCardParams

If you choose to use STPPaymentCardTextField or your own form, you can assemble the data into an STPCardParams object. After you have collected the card number, expiration dates, and CVC, package them up in an STPCardParams object and invoke the createTokenWithCard method on the STPAIClient class, instructing the library to send off the credit card data to Stripe and return a token.

To do so, add the below code to your program.

Example in Swift

@IBAction func save(sender: UIButton) {
if let card = paymentTextField.card {
STPAPIClient.sharedClient().createTokenWithCard(card) { (token, error) -> Void in
if let error = error {
handleError(error)
}
else if let token = token {
createBackendChargeWithToken(token) { status in

...
}
}
}
}
}

Example in Objective-C

- (IBAction)save:(UIButton *)sender {
[[STPAPIClient sharedClient]
createTokenWithCard:self.paymentTextField.card completion:^(STPToken *token, NSError *error) {
if (error) {
[self handleError:error];
} else {
[self createBackendChargeWithToken:token completion:^(PKPaymentAuthorizationStatus status) {
...
}];
}
}];
}

Note:
In the example above, the createTokenWithCard is called when a save button is tapped. It is important that the createToken is not called before user has finished entering their card details.

It is up to you to handle error messages and show activity indicators while creating the token.

Sending the token to your server

The block you gave to createToken in the previous steps is called whenever Stripe returns with a token (or error). To charge the card, you need to send the token off to your server.

Here is how it looks for a token created with Apple Pay.

Example in Swift

// ViewController.swift

func createBackendChargeWithToken(token: STPToken, completion: PKPaymentAuthorizationStatus -> ()) {
let url = NSURL(string: "https://example.com/token")!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
let body = "stripeToken=(token.tokenId)"
request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding)
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let session = NSURLSession(configuration: configuration)
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error != nil {
completion(PKPaymentAuthorizationStatus.Failure)
}
else {
completion(PKPaymentAuthorizationStatus.Success)
}
}
task.resume()
}

Example in Objective-C

// ViewController.m

- (void)createBackendChargeWithToken:(STPToken *)token
completion:(void (^)(PKPaymentAuthorizationStatus))completion {
NSURL *url = [NSURL URLWithString:@"https://example.com /token"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";
NSString *body = [NSString stringWithFormat:@"stripeToken=%@", token.tokenId];
request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURLSessionDataTask *task =
[session dataTaskWithRequest:request
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
if (error) {
completion(PKPaymentAuthorizationStatusFailure);
} else {
completion(PKPaymentAuthorizationStatusSuccess);
}
}];
[task resume];
}

Note:
The completion callback above is Apple Pay-specific. If you are not using Apple Pay, the code is still mostly the same, but you would want to implement custom error and success handling.

On the server, implement an endpoint that will accept the stripeToken parameter. Make sure any communication with your server is SSL-secured to prevent eavesdropping.

After you have a Stripe token representing a card on your server, charge it, save it for charging later, or sign up for a subscription.

For more details, see the full example application.

Android SDK for online payments

· 10 min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Introduction

This documentation provides knowledge in developing Stripe mobile payment inside any Android app. If you need help or have any questions after reading this documentation, we recommend you to check out our answers for common Android questions or contact other developers in #stripe on freenode.

Stripe has created a Java library for Android, allowing you to easily submit payments from an Android app. Our library eliminates the need to send card data directly to your server. Instead, it sends the card data directly to our servers, where we can convert them to tokens.

Your app will receive the token back, and will then be able to send the token to an endpoint on your server, where it can be used to process a payment, establish recurring billing, or merely saved for later use.

Stripe supports Android back to version 4 (Ice Cream Sandwich), and the library has no external dependencies.

Installation

There is a difference in installing the Stripe Android library depending on whether you use Android Studio or Eclipse.

For Android Studio, add the following code to your app's build.gradle file, inside the dependencies section:

compile 'com.stripe:stripe-android:+'

For Eclipse, follow these steps:

  1. Download the Stripe-Android libraries.
  2. Be sure you have installed the Android SDK with a minimum of API Level 17 and android-support-v4.
  3. Import the stripe folder into Eclipse.
  4. In your project settings, add the 'stripe' project under the "Libraries" section of the "Android" category.

Collecting credit card information

At some point in the flow of your app, you will want to obtain payment details from the user. There are 2 ways to do this: • Use Android Pay to access your customer's stored card information • Build your own credit card form

We recommend you to write your app to offer support for both.

Using Android Pay

Through Android Pay, you can access payment information stored in your customer's Google accounts. Following are the instructions to integrate your app with Android Pay.

Note: When this documentation was released, Android Pay was still in Beta Version.

Setting up your app

First, you will need to obtain credentials and a client ID for your app, as explained in the Android Pay API Tutorial. You will also need to set up the latest version of Google Play services.

Collecting payment info via Android Pay

To use Android Pay in your app, first enable the Android Pay API by adding the following code to the <application> tag of your AndroidManifest.xml:

<application
...
<meta-data
android:name="com.google.android.gms.wallet.api.enabled"
android:value="true" />
</application>

In the activity's layout, your application will also need a SupportWalletFragment (the placeholder for the Android Pay purchase button). To create this, add the following code to your program:

<!-- You will need to add the wallet namespace to your enclosing Layout -->
xmlns:wallet="http://schemas.android.com/apk/res-auto"

<fragment
android:id="@+id/wallet_fragment"
android:name="com.google.android.gms.wallet.fragment.SupportWalletFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
wallet:environment="test"
wallet:fragmentMode="buyButton"/>

After placing the fragment, you need to:

  1. Grab a reference to that fragment
  2. Create a MaskWalletRequest
  3. Initialize the fragment

In the MaskWalletRequest, you are able to specify the amount to charge and what additional information you would like to collect (e.g., the shipping address). This is also where you can specify that you are using Stripe as the processor. Doing so will allow the application to request a Stripe token directly from the wallet.

Before starting the Android Pay flow, use the isReadyToPay() method to check whether the user has the Android Pay app installed and is ready to pay through it. Make sure you have already mastered Google's documentation for information on their UI and branding requirements.

The following code is the Android Pay flow:

public class PaymentActivity extends FragmentActivity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {

// You will need to use your live API key even while testing
public static final String PUBLISHABLE_KEY = "pk_live_XXX";

// Unique identifiers for asynchronous requests:
private static final int LOAD_MASKED_WALLET_REQUEST_CODE = 1000;
private static final int LOAD_FULL_WALLET_REQUEST_CODE = 1001;
private SupportWalletFragment walletFragment;

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Wallet.Payments.isReadyToPay(googleApiClient).setResultCallback(
new ResultCallback<BooleanResult>() {
@Override
public void onResult(@NonNull BooleanResult booleanResult) {
if (booleanResult.getStatus().isSuccess()) {
if (booleanResult.getValue()) {
showAndroidPay();
} else {
// Hide Android Pay buttons, show a message that Android Pay
// cannot be used yet, and display a traditional checkout button
}
} else {
// Error making isReadyToPay call
Log.e(TAG, "isReadyToPay:" + booleanResult.getStatus());
}
}
});
...
}

public void showAndroidPay() {
setContentView(R.layout.payment_activity);
walletFragment = (SupportWalletFragment) getSupportFragmentManager()
.findFragmentById(R.id.wallet_fragment);

MaskedWalletRequest maskedWalletRequest = MaskedWalletRequest.newBuilder()
// Request credit card tokenization with Stripe:
.setPaymentMethodTokenizationParameters(
PaymentMethodTokenizationParameters.newBuilder()
.setPaymentMethodTokenizationType(PaymentMethodTokenizationType.PAYMENT_GATEWAY)
.addParameter("gateway", "stripe")
.addParameter("stripe:publishableKey", PUBLISHABLE_KEY)
.addParameter("stripe:version", com.stripe.Stripe.VERSION)
.build())
.setShippingAddressRequired(true)
.setEstimatedTotalPrice("20.00")
.setCurrencyCode("USD")
.build();

WalletFragmentInitParams initParams = WalletFragmentInitParams.newBuilder()
.setMaskedWalletRequest(maskedWalletRequest)
.setMaskedWalletRequestCode(LOAD_MASKED_WALLET_REQUEST_CODE)
.build();

walletFragment.initialize(initParams);
...
}

public void onStart() { ... }
public void onStop() { ... }

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { ... }
@Override public void onConnectionFailed(ConnectionResult connectionResult) {}
@Override public void onConnected(Bundle bundle) {}
@Override public void onConnectionSuspended(int i) {}
}

Note:
The price set within the Android app is written as a decimal and is for the Android app only. The token received back will be sent to your server, and the charge request will be made of the Stripe API from there. The actual amount to be charged is requested at that point, and is set as an integer.

The last step of the Android Pay setup process for the app is to connect to the Google Wallet API. This connection handles the case when a user presses the Android Pay purchase button and the payment is processed. To do so, add the following code:

public class PaymentActivity extends FragmentActivity {
...
private GoogleApiClient googleApiClient;

public void onCreate(Bundle savedInstanceState) {
...
googleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Wallet.API, new Wallet.WalletOptions.Builder()
.setEnvironment(WalletConstants.ENVIRONMENT_TEST)
.setTheme(WalletConstants.THEME_LIGHT)
.build())
.build();
}

public void onStart() {
super.onStart();
googleApiClient.connect();
}

public void onStop() {
super.onStop();
googleApiClient.disconnect();
}
}

Once your customer confirms their purchase, the application then needs to create a FullWalletRequest. This will allow the application to request access to the customer's FullWallet, which is where the payment information comes from. To do this, implement onActivityResult:

public class PaymentActivity extends FragmentActivity {
...
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (requestCode == LOAD_MASKED_WALLET_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
MaskedWallet maskedWallet = data.getParcelableExtra(WalletConstants.EXTRA_MASKED_WALLET);
FullWalletRequest fullWalletRequest = FullWalletRequest.newBuilder()
.setCart(Cart.newBuilder()
.setCurrencyCode("USD")
.setTotalPrice("20.00")
.addLineItem(LineItem.newBuilder()
.setCurrencyCode("USD")
.setQuantity("1")
.setDescription("Premium Llama Food")
.setTotalPrice("20.00")
.setUnitPrice("20.00")
.build())
.build())
.setGoogleTransactionId(maskedWallet.getGoogleTransactionId())
.build();
Wallet.Payments.loadFullWallet(googleApiClient, fullWalletRequest, LOAD_FULL_WALLET_REQUEST_CODE);
}
} else if (requestCode == LOAD_FULL_WALLET_REQUEST_CODE) {
...
}
}
}

Note:
The above example has only one item, but if your customer is purchasing multiple items, you can add multiple items by calling addLineItem additional times.

Creating tokens from Android Pay

Once your customer allows access to their wallet for payment, the application will be given back a Stripe token. You will then send this token to your server for use through the API.

public class PaymentActivity extends FragmentActivity {
...
// Keep track of your current environment.
// Change to WalletConstants.ENVIRONMENT_PRODUCTION when ready to go live.
public static final int mEnvironment = WalletConstants.ENVIRONMENT_TEST;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == LOAD_MASKED_WALLET_REQUEST_CODE) {
...
} else if (requestCode == LOAD_FULL_WALLET_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
FullWallet fullWallet = data.getParcelableExtra(WalletConstants.EXTRA_FULL_WALLET);
String tokenJSON = fullWallet.getPaymentMethodToken().getToken();
// A token will only be returned in production mode,
// i.e. WalletConstants.ENVIRONMENT_PRODUCTION
if (mEnvironment == WalletConstants.ENVIRONMENT_PRODUCTION) {
com.stripe.model.Token token = com.stripe.model.Token.GSON.fromJson(
tokenJSON, com.stripe.model.Token.class);
// TODO: send token to your server
}
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}

Testing and deploying with Android Pay

To test your Android Pay flow, use your live Stripe API key, not your test key, in conjunction with the Android Pay test environment, specified by WalletConstants.ENVIRONMENT_TEST.

In test mode, fullWallet.getPaymentMethodToken().getToken() will return the string "TEST_GATEWAY_TOKEN" in place of a JSON string representing a token.

If you want to test your application on a physical device, make sure the device supports NFC. You will also need to add a supported credit card to your Android Pay account.

When you are ready, you can get production access to Android Pay by submitting your APK to Google for review.

Building your own form

If you plan to build your own form, make sure you will at least be able to collect your customer's card numbers and expiration dates. We recommend you to also collect the CVC to prevent fraud. The user's name and billing address are optional and would benefit you in terms of fraud protection.

Once you have collected a customer's information, you will need to exchange the information for a Stripe token.

Creating and validating cards from customer form

The first step is to import the Stripe classes before using them:

import com.stripe.android.*;

There are two main classes: Card and Stripe. The Card class contains many useful helpers for validating card input on the client-side before a charge is created.

To construct a Card instance with your customer's payment information, add the following code to your program:

Card card = new Card(
cardNumber,
cardExpMonth,
cardExpYear,
cardCVC
);
card.validateNumber();
card.validateCVC();

In the above example, the Card instance contains helpers to validate that: • the card number passes the Luhn check • the expiration date is in the future • the CVC looks valid

You will probably want to validate these three things at once, so we have included a validateCard function that does so:

Card card = new Card("4242-4242-4242-4242", 12, 2017, "123");
if ( !card.validateCard() ) {
// Show errors
}

Creating tokens from a customer form

The next step is to pass off that sensitive payment information securely to Stripe, where you will exchange it for a token.

You can create tokens using the Stripe instance method createToken, passing in a Card instance and completion callbacks. An asynchronous network request will be executed, and the appropriate callback invoked when it completes.

Card card = new Card("4242424242424242", 12, 2017, "123");
Stripe stripe = new Stripe("pk_test_6pRNASCoBOKtIshFeQd4XMUh");

stripe.createToken(
card,
new TokenCallback() {
public void onSuccess(Token token) {
// Send token to your server
}
public void onError(Exception error) {
// Show localized error message
Toast.makeText(getContext(),
error.getLocalizedString(getContext()),
Toast.LENGTH_LONG
).show();
}
}
);

We have placed your test publishable API key as the first argument to Stripe. You will need to swap it out with your live publishable key in production. You can see all your keys after logging into your Stripe dashboard.

Using Tokens

Using the payment token requires an API call from your server using your secret API key. For security purposes, you should never embed your secret API key in your app.

To do so, you need to set up an endpoint on your server that can receive an HTTP POST call for the token. In the onActivityResult method or the onSuccess callback, you will need to POST the supplied token to your server. Make sure any communication with your server is SSL secured to prevent eavesdropping.

For a full example, see the Stripe Android example on GitHub.

Stripe's customers API

· 20 min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Introduction

The Stripe customers API is organized around REST. It has predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors. It uses built-in HTTP features, like HTTP authentication and HTTP verbs, which are understood by off-the-shelf HTTP clients. It supports cross-origin resource sharing, allowing you to interact securely with our API from a client-side web application (though you should never expose your secret API key in any public website’s client-side code).

To make the API as explorable as possible, accounts have test mode and live mode API keys. There is no “switch” for changing between modes, just use the appropriate key to perform a live or test transaction. Requests made with test mode credentials never hit the banking networks and incur no cost.

Customers

Customer objects allow you to perform recurring charges and track multiple charges that are associated with the same customer. The API allows you to create, delete, and update your customers. You can retrieve individual customers as well as list of all your customers.

The customer object

The following are the attributes in this feature.

AttributeTypeDescription
idstringThe unique record ID
objectstringThe value is customer
account_balanceintegerCurrent balance, if any, being stored on the customer’s account. If negative, the customer has credit to apply to the next invoice. If positive, the customer has an amount owed that will be added to the next invoice. The balance does not refer to any unpaid invoices; it solely takes into account amounts that have yet to be successfully applied to any invoice. This balance is only taken into account for recurring billing purposes (i.e., subscriptions, invoices, invoice items).
business_vat_idstringThe customer’s VAT identification number
createdtimestampThe date and time the record was created
currencystringThe currency the customer can be charged in for recurring billing purposes.
default_sourcestringID of the default source attached to this customer
delinquentbooleanWhether or not the latest charge for the customer’s latest invoice has failed
descriptionstringRemarks about the record
discounthashDescribes the current discount active on the customer, if there is one.
emailstring
livemodebooleanWhether or not livemode is on
metadatastringA set of key/value pairs that you can attach to a customer object. It can be useful for storing additional information about the customer in a structured format.
shippinghashShipping information associated with the customer
sourceslistThe customer’s payment sources, if any
subscriptionslistThe customer’s payment subscriptions, if any

customer-shipping

The following is the customer-shipping object's child attribute.

AttributeTypeDescription
addresshashCustomer shipping address

customer-shipping-address

The following are the customer-shipping-address object's attributes.

AttributeTypeDescription
citystringThe shipping address' city / suburb / town / village
countrystringTwo-letter country code of the shipping address
line1stringThe shipping address' street / PO Box / company name
line2stringThe shipping address' apartment / suite / unit / building
postal_codestringThe shipping address' zip / postal code
statestringThe shipping address' state / province / county

customer-sources

The following are the customer-sources object's child attributes.

AttributeTypeDescription
objectstringValue is list
dataarrayThe list contains all payment sources that have been attached to the customer. These may be Cards or BitcoinReceivers.
has_morebooleanWhether or not there are more records
total_countpositive integer or zeroThe total number of items available. This value is not included by default, but you can request it by specifying ?include[]=total_count.
urlstringThe URL where this list can be accessed.

customer-subscriptions

The following are the customer-subscriptions object's child attributes.

AttributeTypeDescription
objectstringValue is list
dataarrayThe list contains all payment sources that have been attached to the customer. These may be Cards or BitcoinReceivers.
has_morebooleanWhether or not there are more records
total_countpositive integer or zeroThe total number of items available. This value is not included by default, but you can request it by specifying ?include[]=total_count.
urlstringThe URL where this list can be accessed.

The following is an example response:

com.stripe.model.Customer JSON: {
"id": "cus_8JMTaIcum1p34N",
"object": "customer",
"account_balance": 0,
"business_vat_id": null,
"created": 1461252581,
"currency": "usd",
"default_source": "card_182jjK2eZvKYlo2CHJmfmQ93", "delinquent": false,
"description": "Mia Anderson",
"discount": null,
"email": "mia.anderson.34@example.com", "livemode": false,
"metadata": {
},
"shipping": null,
"sources": {
"object": "list",
"data": [
{
"id": "card_182jjK2eZvKYlo2CHJmfmQ93", "object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8JMTaIcum1p34N",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2017,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/customers/cus_8JMTaIcum1p34N/sources" },
"subscriptions": {
"object": "list",
"data": [
{
"id": "sub_8JMVP3u5AvUoKd",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": false,
"canceled_at": null,
"current_period_end": 1463844717,
"current_period_start": 1461252717,
"customer": "cus_8JMTaIcum1p34N",
"discount": null,
"ended_at": null,
"metadata": {
},
"plan": {
"id": "titanium-expert-948", "object": "plan",
"amount": 999,
"created": 1461252658,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
},
"name": "Titanium Expert",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1461252717,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/customers/cus_8JMTaIcum1p34N/subscriptions"
}
}

Create a customer

Creates a new customer object. To do so, add Customer.create(); to your program.

The following are the optional arguments in this feature.

ArgumentDescription
account_balanceAn integer amount in cents that is the starting account balance for your customer. A negative amount represents a credit that will be used before attempting any charges to the customer’s card; a positive amount will be added to the next invoice.
business_vat_idThe customer’s VAT identification number
couponIf you provide a coupon code, the customer will have a discount applied on all recurring charges. Charges you create through the API will not have the discount.
descriptionAn arbitrary string that you can attach to a customer object. It is displayed alongside the customer in the dashboard. This will be unset if you POST an empty value.This can be unset by updating the value to Null and then saving.
emailCustomer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. This will be unset if you POST an empty value. This can be unset by updating the value to Null and then saving.
metadataA set of key/value pairs that you can attach to a customer object. It can be useful for storing additional information about the customer in a structured format. This will be unset if you POST an empty value.This can be unset by updating the value to Null and then saving.
planThe identifier of the plan to subscribe the customer to. If provided, the returned customer object will have a list of subscriptions that the customer is currently subscribed to. If you subscribe a customer to a plan without a free trial, the customer must have a valid card as well.
quantityThe quantity you’d like to apply to the subscription you’re creating (if you pass in a plan). For example, if your plan is 10 cents/user/month, and your customer has 5 users, you could pass 5 as the quantity to have the customer charged 50 cents (5 x 10 cents) monthly. Defaults to 1 if not set. Only applies when the plan parameter is also provided.
shippingThe shipping address
sourceThe source can either be a token, like the ones returned by our Stripe.js, or a dictionary containing a user’s credit card details.
tax_percentA positive decimal (with at most two decimal places) between 1 and 100. This represents the percentage of the subscription invoice subtotal that will be calculated and added as tax to the final amount each billing period. For example, a plan which charges $10/month with a tax_percent of 20.0 will charge $12 per invoice. Can only be used if a plan is provided.
trial_endUnix timestamp representing the end of the trial period the customer will get before being charged. If set, trial_end will override the default trial period of the plan the customer is being subscribed to. The special value now can be provided to end the customer’s trial immediately. Only applies when the plan parameter is also provided.

create-shipping

The following are the shipping object's child arguments.

ArgumentConditionDescription
addressRequiredThe full shipping address
nameRequiredThe name of the shipping contact
phoneOptionalThe phone number of the shipping contact

create-shipping-address

The following are the create-shipping-address object's child arguments.

ArgumentConditionDescription
line1RequiredThe shipping address' street
line2OptionalThe shipping address' building / company name / etc.
cityOptionalThe shipping address' city
countryOptionalThe shipping address' country
postal_codeOptionalThe shipping address' zip / postal code
stateOptionalThe shipping address' state / territory / province

create-source

The following are the create-source object's child arguments.

ArgumentConditionDescription
objectRequiredThe type of payment source. Should be card
exp_monthRequiredTwo-digit number representing the card’s expiration month
exp_yearRequiredTwo- or four-digit number representing the card’s expiration year
numberRequiredThe card number, as a string without any separators
address_cityOptionalThe source's city
address_countryOptionalThe source's country
address_line1OptionalThe source's street / apartment
address_line2OptionalThe source's building / company name
address_stateOptionalThe source's state
address_zipOptionalThe source's zip / postal code
currencyManaged Accounts OnlyRequired when adding a card to an account (not applicable to a customers or recipients). The card (which must be a debit card) can be used as a transfer destination for funds in this currency. Currently, the only supported currency for debit card transfers is usd.
cvcRequiredCard security code. Required unless your account is registered in Australia, Canada, or the United States. Highly recommended to always include this value.
default_for_currencyManaged Accounts OnlyOnly applicable on accounts (not customers or recipients). If you set this to true (or if this is the first external account being added in this currency) this card will become the default external account for its currency.
metadataOptionalA set of key/value pairs that you can attach to a card object. It can be useful for storing additional information about the card in a structured format.
nameOptionalCardholder’s full name

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Map<String, Object> customerParams = new HashMap<String, Object>();
customerParams.put("description", "Customer for test@example.com");
customerParams.put("source", "tok_182ied2eZvKYlo2CDbFVWcMM"); // obtained with Stripe.js

Customer.create(customerParams);

Returns

Returns a customer object if the call succeeded. The returned object will have information about subscriptions, discount, and payment sources, if that information has been provided. If an invoice payment is due and a source is not provided, the call will raise an error. If a non-existent plan or a non-existent or expired coupon is provided, the call will raise an error.

If a source has been attached to the customer, the returned customer object will have a default_source attribute, which is an ID that can be expanded into the full source details when retrieving the customer.

The following is an example response:

com.stripe.model.Customer JSON: { 
"id": "cus_8JNNkDAKVZ23vZ",
"object": "customer",
"account_balance": 0,
"business_vat_id": null,
"created": 1461255958,
"currency": "usd",
"default_source": null,
"delinquent": false,
"description": "test papirus (test@n206papirus.net)", "discount": null,
"email": "test@n206papirus.net",
"livemode": false,
"metadata": {
},
"shipping": null,
"sources": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_8JNNkDAKVZ23vZ/sources"
},
"subscriptions": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_8JNNkDAKVZ23vZ/subscriptions" }
}

Retrieve a customer

Retrieves the details of an existing customer. You need only supply the unique customer identifier that was returned upon customer creation.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Customer.retrieve("cus_8JNO6XkCpsjc7s");

Returns

Returns a customer object if a valid identifier was provided. When requesting the ID of a customer that has been deleted, a subset of the customer’s information will be returned, including a deleted property, which will be true.

The following is an example response:

com.stripe.model.Customer JSON: { 
"id": "cus_8JNO6XkCpsjc7s",
"object": "customer",
"account_balance": 0,
"business_vat_id": null,
"created": 1461256039,
"currency": "usd",
"default_source": "card_182keA2eZvKYlo2CGbcuGkIT",
"delinquent": false,
"description": null,
"discount": null,
"email": "sbvmqa+gwenna@gmail.com",
"livemode": false,
"metadata": {
},
"shipping": null,
"sources": {
"object": "list",
"data": [
{
"id": "card_182keA2eZvKYlo2CGbcuGkIT", "object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8JNO6XkCpsjc7s",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2019,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/customers/cus_8JNO6XkCpsjc7s/sources" },
"subscriptions": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_8JNO6XkCpsjc7s/subscriptions"
}
}

Update a customer

Updates the specified customer by setting the values of the parameters passed. Any parameters not provided will be left unchanged. For example, if you pass the source parameter, that becomes the customer’s active source (e.g., a card) to be used for all charges in the future.

When you update a customer to a new valid source: for each of the customer’s current subscriptions, if the subscription is in the past_due state, then the latest unpaid, unclosed invoice for the subscription will be retried (note that this retry will not count as an automatic retry, and will not affect the next regularly scheduled payment for the invoice. Note also that no invoices pertaining to subscriptions in the unpaid state, or invoices pertaining to canceled subscriptions, will be retried as a result of updating the customer’s source.)

This request accepts mostly the same arguments as the customer creation call.

To do so, add the following code to your program:

Customer cu = Customer.retrieve({CUSTOMER_ID}); 
Map<String, Object> updateParams = new HashMap<String, Object>();
updateParams.put("description", {NEW_DESCRIPTION});
...
cu.update(updateParams);

The following are the optional arguments in this feature.

ArgumentDescription
account_balanceAn integer amount in cents that represents the account balance for your customer. Account balances only affect invoices. A negative amount represents a credit that decreases the amount due on an invoice; a positive amount increases the amount due on an invoice.
busines_vat_idThe customer’s VAT identification number.
couponIf you provide a coupon code, the customer will have a discount applied on all recurring charges. Charges you create through the API will not have the discount.
default_sourceID of source to make the customer’s new default for invoice payments
descriptionAn arbitrary string that you can attach to a customer object. It is displayed alongside the customer in the dashboard. This will be unset if you POST an empty value. This can be unset by updating the value to Null and then saving.
emailCustomer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking. This will be unset if you POST an empty value. This can be unset by updating the value to Null and then saving.
metadataA set of key/value pairs that you can attach to a customer object. It can be useful for storing additional information about the customer in a structured format. This will be unset if you POST an empty value.This can be unset by updating the value to Null and then saving.
shipping
sourceThe source can either be a token, like the ones returned by our Stripe.js, or a dictionary containing a user’s credit card details (with the options shown below). Passing source will create a new source object, make it the new customer default source, and delete the old customer default if one exists. If you want to add additional sources instead of replacing the existing default, use the card creation API. Whenever you attach a card to a customer, Stripe will automatically validate the card.

update-shipping

The following are the update-shipping child arguments.

ArgumentConditionDescription
addressRequiredThe full shipping address
nameRequiredThe shipping contact name
phoneOptionalThe shipping contact phone number

update-shipping-address

The following are the update-shipping-address object's child arguments.

ArgumentConditionDescription
line1RequiredThe update shipping address' street
cityOptionalThe update shipping address' city
countryOptionalThe update shipping address' country
line2OptionalThe update shipping address' building / company name / block
postal_codeOptionalThe update shipping address' zip / postal code
stateOptionalThe update shipping address' state

update-source

The following are the update-source object's child arguments.

ArgumentConditionDescription
objectRequiredThe type of payment source. Should be card
exp_monthRequiredTwo-digit number representing the card’s expiration month
exp_yearRequiredTwo- or four-digit number representing the card’s expiration year
numberRequiredThe card number, as a string without any separators
address_cityOptionalThe update source address' city
address_countryOptionalThe update source address' country
address_line1OptionalThe update source address' street
address_line2OptionalThe update source address' building / suite / company name
address_stateOptionalThe update source address' state
address_zipOptionalThe update source address' zip / postal code
currencyManaged Accounts OnlyRequired when adding a card to an account (not applicable to a customers or recipients). The card (which must be a debit card) can be used as a transfer destination for funds in this currency. Currently, the only supported currency for debit card transfers is usd.
cvcRequiredCard security code. Required unless your account is registered in Australia, Canada, or the United States. Highly recommended to always include this value.
default_for_currencyManaged Accounts OnlyOnly applicable on accounts (not customers or recipients). If you set this to true (or if this is the first external account being added in this currency) this card will become the default external account for its currency.
metadataOptionalA set of key/value pairs that you can attach to a card object. It can be useful for storing additional information about the card in a structured format.
nameOptionalCardholder’s full name

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 
Customer cu = Customer.retrieve("cus_8JNceg1cXYpZwJ");
Map<String, Object> updateParams = new HashMap<String, Object>();
updateParams.put("description", "Customer for test@example.com");

cu.update(updateParams);

Returns

Returns the customer object if the update succeeded. Throws an error if update parameters are invalid (e.g. specifying an invalid coupon or an invalid source).

The following is an example response:

com.stripe.model.Customer JSON: { 
"id": "cus_8JNceg1cXYpZwJ",
"object": "customer",
"account_balance": 0,
"business_vat_id": null,
"created": 1461256854,
"currency": "usd",
"default_source": "card_182krH2eZvKYlo2CyXuVSi02", "delinquent": false,
"description": "Customer for test@example.com", "discount": null,
"email": "aheaven87@gmail.com",
"livemode": false,
"metadata": {
},
"shipping": null,
"sources": {
"object": "list",
"data": [
{
"id": "card_182krH2eZvKYlo2CyXuVSi02", "object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8JNceg1cXYpZwJ",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 1,
"exp_year": 2017,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/customers/cus_8JNceg1cXYpZwJ/sources"
},
"subscriptions": {
"object": "list",
"data": [
{
"id": "sub_8JNeptwCu8Zddh",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": false,
"canceled_at": null,
"current_period_end": 1463848953,
"current_period_start": 1461256953,
"customer": "cus_8JNceg1cXYpZwJ",
"discount": null,
"ended_at": null,
"metadata": {
},
"plan": {
"id": "ern-monthly",
"object": "plan",
"amount": 2499,
"created": 1461244184,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
"plan_id": "2"
},
"name": "Monthly Subscription",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1461256953,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
},
{
"id": "sub_8JNdYGbwDkccbh",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": false,
"canceled_at": null,
"current_period_end": 1463848903,
"current_period_start": 1461256903,
"customer": "cus_8JNceg1cXYpZwJ",
"discount": null,
"ended_at": null,
"metadata": {
},
"plan": {
"id": "ern-monthly",
"object": "plan",
"amount": 2499,
"created": 1461244184,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
"plan_id": "2"
},
"name": "Monthly Subscription",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1461256903,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
},
{
"id": "sub_8JNcIPeX5FZHLi",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": false,
"canceled_at": null,
"current_period_end": 1463848878,
"current_period_start": 1461256878,
"customer": "cus_8JNceg1cXYpZwJ",
"discount": null,
"ended_at": null,
"metadata": {
},
"plan": {
"id": "ern-monthly",
"object": "plan",
"amount": 2499,
"created": 1461244184,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
"plan_id": "2"
},
"name": "Monthly Subscription",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1461256878,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
}
],
"has_more": false,
"total_count": 3,
"url": "/v1/customers/cus_8JNceg1cXYpZwJ/subscriptions" }
}

Delete a customer

Permanently deletes a customer. It cannot be undone. Also immediately cancels any active subscriptions on the customer.

To do so, add the following code to your program:

Customer cu = Customer.retrieve({CUSTOMER_ID}); 
cu.delete();

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Customer cu = Customer.retrieve("cus_8JNmQG7nBfcoHK"); cu.delete();

Returns

Returns an object with a deleted parameter on success. If the customer ID does not exist, this call raises an error.

Unlike other objects, deleted customers can still be retrieved through the API, in order to be able to track the history of customers while still removing their credit card details and preventing any further operations to be performed (such as adding a new subscription).

The following is an example response:

com.stripe.model.Object JSON: { 
"deleted": true,
"id": "cus_8JNshRXjBWnJdM"
}

List all customers

Returns a list of your customers. The customers are returned sorted by creation date, with the most recent customers appearing first.

To do so, add Customer.all(Map<String, Object> options); to your program.

The following are the optional arguments in this feature.

ArgumentDescription
createdA filter on the list based on the object created field. The value can be a string with an integer Unix timestamp, or it can be a dictionary with the other options.
customerOnly return charges for the customer specified by this customer ID
ending_beforeA cursor for use in pagination. ending_before is an object ID that defines your place in the list. For instance, if you make a list request and receive 100 objects, starting with obj_bar, your subsequent call can include ending_before=obj_bar in order to fetch the previous page of the list.
limitA limit on the number of objects to be returned. Limit can range between 1 and 100 items. Default is 10.
starting_afterA cursor for use in pagination. starting_after is an object ID that defines your place in the list. For example, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can include starting_after=obj_foo to fetch the next page of the list.

list-created

The following are the list-created object's optional timestamp child arguments.

ArgumentDescription
gt(greater than) Return values where the created field is after this timestamp
gte(greater than or equal) Return values where the created field is after or equal to this timestamp
lt(less than) Return values where the created field is before this timestamp
lte(less than or equal) Return values where the created field is before or equal to this timestamp

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Map<String, Object> customerParams = new HashMap<String, Object>();
customerParams.put("limit", 3);

Customer.all(customerParams);

Returns

A dictionary with a data property that contains an array of up to limit customers, starting after customer starting_after. Each entry in the array is a separate customer object. If no more customers are available, the resulting array will be empty. This request should never raise an error.

You can optionally request that the response include the total count of all customers that match your filters. To do so, specify include[]=total_count in your request.

The following is an example response:

#<com.stripe.model.CustomerCollection id=#> JSON: { 
"data": [
com.stripe.model.Customer JSON: {
"id": "cus_8JO0w4XG8QrzSx",
"object": "customer",
"account_balance": 0,
"business_vat_id": null,
"created": 1461258315,
"currency": "usd",
"default_source": "card_182lEt2eZvKYlo2CpBNb7MFy", "delinquent": false,
"description": null,
"discount": null,
"email": null,
"livemode": false,
"metadata": {
},
"shipping": null,
"sources": {
"object": "list",
"data": [
{
"id": "card_182lEt2eZvKYlo2CpBNb7MFy",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8JO0w4XG8QrzSx",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 7,
"exp_year": 2017,
"funding": "unknown",
"last4": "1111",
"metadata": {
},
"name": null,
"tokenization_method": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/customers/cus_8JO0w4XG8QrzSx/sources" },
"subscriptions": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_8JO0w4XG8QrzSx/subscriptions"
}
},
#<com.stripe.model.Customer[...] ...>,
#<com.stripe.model.Customer[...] ...>
],
"has_more": false
}

Stripe's charges API

· 19 min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Introduction

The Stripe charges API is organized around REST. It has predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors. It uses built-in HTTP features, like HTTP authentication and HTTP verbs, which are understood by off-the-shelf HTTP clients. It supports cross-origin resource sharing, allowing you to interact securely with our API from a client-side web application (though you should never expose your secret API key in any public website’s client-side code).

To make the API as explorable as possible, accounts have test mode and live mode API keys. There is no “switch” for changing between modes, just use the appropriate key to perform a live or test transaction. Requests made with test mode credentials never hit the banking networks and incur no cost.

Charges

To charge a credit or a debit card, you create a charge object. You can retrieve and refund individual charges as well as list all charges. Charges are identified by a unique random ID.

The charge object

The following table lists the attributes in the charge object.

AttributeTypeDefinition
idstringThe unique ID
objectstringThe value is charge
amountpositive integer or zeroAmount charged in cents
amount_refundedpositive integer or zeroAmount in cents refunded (can be less than the amount attributes on the charge if a partial refund was issued)
application_feestringThe application fee (if any) for the charge
balance_transactionstringID of the balance transaction that describes the impact of this charge on your account balance (not including refunds or disputes)
capturedbooleanIf the charge was created without capturing, this boolean represents whether or not it is still uncaptured or has since been captured
createdtimestampThe date the charge was created
currencycurrencyThree-letter ISO currency code representing the currency in which the charge was made
customerstringID of the customer this charge is for if one exists
descriptionstringRemarks about the charge
destinationstringThe account (if any) the charge was made on behalf of
disputeshashDetails about the dispute if the charge has been disputed
failure_codestringError code explaining reason for charge failure, if available
failure_messagestringMessage to user further explaining reason for charge failure, if available
fraud_detailshashHash with information on fraud assessments for the charge. Assessments reported by you have the key user_report and, if set, possible values of safe and fraudulent. Assessments from Stripe have the key stripe_report and, if set, the value fraudulent.
invoicestringID of the invoice this charge is for, if one exists
livemodebooleanDefault is false
metadataintegerA set of key/value pairs that you can attach to a charge object. It can be useful for storing additional information about the charge in a structured format
orderstringID of the order this charge is for, if one exists
paidbooleantrue if the charge succeeded, or was successfully authorized for later capture
receipt_emailstringThe email address that the receipt for this charge was sent to
receipt_numberstringThe transaction number that appears on email receipts sent for this charge
refundedbooleanWhether or not the charge has been fully refunded. If the charge is only partially refunded, this attribute will still be false.
refundslistA list of refunds that have been applied to the charge
shippinghashShipping information for the charge
sourcehashFor most Stripe users, the source of every charge is a credit or debit card. This hash is then the card object describing that card.
source_transferstringThe transfer ID which created this charge. Only present if the charge came from another Stripe account.
statement_descriptorstringExtra information about a charge. This will appear on your customer’s credit card statement.
statusstringThe status of the payment is either succeeded, pending, or failed.
transferstringID of the transfer to the destination account (only applicable if the charge was created using the destination parameter).

refunds

The following are the refunds object child attributes.

AttributeTypeDefinition
objectstringThe value is list
datastring

shipping

The following are the shipping object child attributes.

AttributeTypeDefinition
addresshashShipping information for the charge

address

The following are the address object child attributes.

AttributeTypeDefinition
citystringCity / Suburb / Town / Village
countrystringTwo-letter country code
line1stringAddress line 1 (Street address / PO Box / Company name)
line2stringAddress line 2 (Apartment / Suite / Unit / Building)
postal_codestringZip / Postal Code
statestringState / Province / County

Create a charge

To charge a credit card, you create a charge object. If your API key is in test mode, the supplied payment source (e.g., card or Bitcoin receiver) won’t actually be charged, though everything else will occur as if in live mode. (Stripe assumes that the charge would have completed successfully). To do so, simply add Charge.create(); to your program.

The following are the arguments of this feature.

ArgumentConditionDefinition
amountRequiredA positive integer in the smallest currency unit (e.g 100 cents to charge $1.00, or 1 to charge ¥1, a 0-decimal currency) representing how much to charge the card. The minimum amount is $0.50 (or equivalent in charge currency).
currencyRequiredThree-letter ISO code for currency.
application_feeConnect onlyA fee in cents that will be applied to the charge and transferred to the application owner’s Stripe account. To use an application fee, the request must be made on behalf of another account, using the Stripe-Account header, an OAuth key, or the destination parameter.
captureOptionalAn arbitrary string which you can attach to a charge object. It is displayed when in the web interface alongside the charge. Note that if you use Stripe to send automatic email receipts to your customers, your receipt emails will include the description of the charge(s) that they are describing. Default is true
destinationConnect OnlyAn account to make the charge on behalf of. If specified, the charge will be attributed to the destination account for tax reporting, and the funds from the charge will be transferred to the destination account. The ID of the resulting transfer will be returned in the transfer field of the response.
metadataOptionalA set of key/value pairs that you can attach to a charge object. It can be useful for storing additional information about the customer in a structured format. It’s often a good idea to store an email address in metadata for tracking later. Default is {}
receipt_emailOptionalThe email address to send this charge’s receipt to. The receipt will not be sent until the charge is paid. If this charge is for a customer, the email address specified here will override the customer’s email address. Receipts will not be sent for test mode charges. If receipt_email is specified for a charge in live mode, a receipt will be sent regardless of your email settings. Default is None
shippingOptionalShipping information for the charge. Helps prevent fraud on charges for physical goods. Default is {}
customerEither customer or source is requiredThe ID of an existing customer that will be charged in this request.
sourceEither customer or source is requiredA payment source to be charged, such as a credit card. If you also pass a customer ID, the source must be the ID of a source belonging to the customer. Otherwise, if you do not pass a customer ID, the source you provide must either be a token, like the ones returned by Stripe.js, or a dictionary containing a user’s credit card details, with the options described below. Although not all information is required, the extra info helps prevent fraud.
statement_descriptorOptionalAn arbitrary string to be displayed on your customer’s credit card statement. This may be up to 22 characters. As an example, if your website is RunClub and the item you’re charging for is a race ticket, you may want to specify a statement_descriptor of RunClub 5K race ticket. The statement description may not include <>"' characters, and will appear on your customer’s statement in capital letters. Non-ASCII characters are automatically stripped. While most banks display this information consistently, some may display it incorrectly or not at all. Default is None

create-source

The following are the create-source object child attributes.

AttributeConditionDefinition
exp_monthRequiredTwo-digit number representing the card’s expiration month
exp_yearRequiredTwo- or four-digit number representing the card’s expiration year
numberRequiredThe card number, as a string without any separators
objectRequiredThe type of payment source. Should be card
cvcRequiredCard security code. Required unless your account is registered in Australia, Canada, or the United States. Highly recommended to always include this value.
address_cityOptionalThe create source address' city
address_countryOptionalThe create source address' country
address_line1OptionalThe create source address' street
address_line2OptionalThe create source address' suite / apartment / company name

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Map<String, Object> chargeParams = new HashMap<String, Object>();
chargeParams.put("amount", 400);
chargeParams.put("currency", "usd");
chargeParams.put("source", "tok_182NNY2eZvKYlo2CRKti7ouM"); // obtained with Stripe.js
chargeParams.put("description", "Charge for test@example.com");
Charge.create(chargeParams);

The following table shows the verification responses for the CVC source[cvc_check]:

VerificationMeaning
passThe CVC provided is correct.
failThe CVC provided is incorrect.
unavailableThe customer’s bank did not check the CVC provided.
uncheckedThe CVC was provided but has not been checked. Checks are performed once a card is attached to a Customer object, or when a Charge is created.

The following table shows the verification responses for the ADDRESS LINE source[address_line1_check]:

VerificationMeaning
passThe first address line provided is correct.
failThe first address line provided is incorrect.
unavailableThe customer’s bank did not check the first address line provided.
uncheckedThe first address line was provided but has not been checked. Checks are performed once a card is attached to a Customer object, or when a Charge is created.

The following table shows the verification responses for the ADDRESS ZIP source[address_zip_check]:

VerificationMeaning
passThe ZIP provided is correct.
failThe ZIP provided is incorrect.
unavailableThe customer’s bank did not check the ZIP provided.
uncheckedThe ZIP was provided but has not been checked. Checks are performed once a card is attached to a Customer object, or when a Charge is created.

Returns

Returns a charge object if the charge succeeded. Raises an error if something goes wrong. A common source of error is an invalid or expired card, or a valid card with insufficient available balance.

If the cvc parameter is provided, Stripe will attempt to check the CVC’s correctness, and the check’s result will be returned. Similarly, if address_line1 or address_zip are provided, Stripe will try to check the validity of those parameters. Some banks do not support checking one or more of these parameters, in which case Stripe will return an ‘unavailable’ result. Also note that, depending on the bank, charges can succeed even when passed incorrect CVC and address information.

The following is an example response:

com.stripe.model.Charge JSON: { 
"id": "ch_182SZq2eZvKYlo2C1KFpXrGY",
"object": "charge",
"amount": 1000,
"amount_refunded": 0,
"application_fee": null,
"balance_transaction": "txn_17bBwe2eZvKYlo2Cuwcyi9or", "captured": true,
"created": 1461186578,
"currency": "usd",
"customer": "cus_8J4jsf6GGZJFeO",
"description": "Charge for VirtuMedix consultation for sj sdaj wkoqsdkasjkad",
"destination": null,
"dispute": null,
"failure_code": null,
"failure_message": null,
"fraud_details": {
},
"invoice": null,
"livemode": false,
"metadata": {
},
"order": null,
"paid": true,
"receipt_email": null,
"receipt_number": null,
"refunded": false,
"refunds": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_182SZq2eZvKYlo2C1KFpXrGY/refunds "
},
"shipping": null,
"source": {
"id": "card_182SZp2eZvKYlo2CbbMHL18T",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8J4jsf6GGZJFeO", "cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2019,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
},
"source_transfer": null,
"statement_descriptor": null, "status": "succeeded"
}

Retrieve a charge

Retrieves the details of a charge that has previously been created. Supply the unique charge ID that was returned from your previous request, and Stripe will return the corresponding charge information. The same information is returned when creating or refunding the charge.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Charge.retrieve("ch_182Shs2eZvKYlo2Ca1bLfus3");

Returns

Returns a charge if a valid identifier was provided, and throws an error otherwise.

The following is an example response:

com.stripe.model.Charge JSON: { 
"id": "ch_182SjH2eZvKYlo2CCh93kJaa",
"object": "charge",
"amount": 500,
"amount_refunded": 0,
"application_fee": null,
"balance_transaction": "txn_17bBwe2eZvKYlo2Cuwcyi9or", "captured": true,
"created": 1461187163,
"currency": "usd",
"customer": "cus_8J4ttJ6RYZBpkt",
"description": "Charge for RelyMD consultation for Rakesh Mohan",
"destination": null,
"dispute": null,
"failure_code": null,
"failure_message": null,
"fraud_details": {
},
"invoice": null,
"livemode": false,
"metadata": {
},
"order": null,
"paid": true,
"receipt_email": null,
"receipt_number": null,
"refunded": false,
"refunds": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_182SjH2eZvKYlo2CCh93kJaa/refunds"
},
"shipping": null,
"source": {
"id": "card_182SjH2eZvKYlo2C8RjEPYVN", "object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8J4ttJ6RYZBpkt", "cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2016,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
},
"source_transfer": null,
"statement_descriptor": null,
"status": "succeeded"
}

Update a charge

Updates the specified charge by setting the values of the parameters passed. Any parameters not provided will be left unchanged.

This request accepts only the description, metadata, receipt_email, fraud_details, and shipping as arguments.

To do so, add:

Charge ch = Charge.retrieve({CHARGE_ID}); 
Map<String, Object> updateParams = new HashMap<String, Obje ct>();
updateParams.put("description", {NEW_DESCRIPTION});
...
ch.update(updateParams);

The following are the optional arguments of this feature.

AttributeDefinition
descriptionAn arbitrary string which you can attach to a charge object. It is displayed when in the web interface alongside the charge. Note that if you use Stripe to send automatic email receipts to your customers, your receipt emails will include the description of the charge(s) that they are describing. This will be unset if you POST an empty value.This can be unset by updating the value to None and then saving. Default is None.
fraud_detailsA set of key/value pairs you can attach to a charge giving information about its riskiness. If you believe a charge is fraudulent, include a user_report key with a value of fraudulent . If you believe a charge is safe, include a user_report key with a value of safe. Note that you must refund a charge before setting the user_report to fraudulent. Stripe will use the information you send to improve our fraud detection algorithms. Default is {}
metadataA set of key/value pairs that you can attach to a charge object. It can be useful for storing additional information about the charge in a structured format. You can unset individual keys if you POST an empty value for that key. You can clear all keys if you POST an empty value for metadata.You can unset an individual key by setting its value to None and then saving. To clear all keys, set metadata to None, then save. Default is {}
receipt_emailThis is the email address that the receipt for this charge will be sent to. If this field is updated, then a new email receipt will be sent to the updated address. Default is None
shippingShipping information for the charge. Helps prevent fraud on charges for physical goods. Default is {}

Returns

Returns the charge object if the update succeeded. This call will raise an error if update parameters are invalid.

The following is an example response:

com.stripe.model.Charge JSON: { 
"id": "ch_182TAE2eZvKYlo2C0PxBlCrq",
"object": "charge",
"amount": 2000,
"amount_refunded": 0,
"application_fee": null,
"balance_transaction": "txn_17bBwe2eZvKYlo2Cuwcyi9or", "captured": true,
"created": 1461188834,
"currency": "usd",
"customer": "cus_8J5KKY7sEj2IOp",
"description": "Charge for test@example.com", "destination": null,
"dispute": null,
"failure_code": null,
"failure_message": null,
"fraud_details": {
},
"invoice": null,
"livemode": false,
"metadata": {
},
"order": null,
"paid": true,
"receipt_email": null,
"receipt_number": null,
"refunded": false,
"refunds": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_182TAE2eZvKYlo2C0PxBlCrq/refunds "
},
"shipping": null,
"source": {
"id": "card_182T9H2eZvKYlo2CYVWu5ZHC",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8J5KKY7sEj2IOp",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2017,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
},
"source_transfer": null,
"statement_descriptor": null,
"status": "succeeded"
}

Capture a charge

Capture the payment of an existing, uncaptured, charge. This is the second half of the two-step payment flow, where first you created a charge with the capture option set to false.

Uncaptured payments expire exactly seven days after they are created. If they are not captured by that point in time, they will be marked as refunded and will no longer be capturable.

To do so, add:

ch = Charge.retrieve({CHARGE_ID}); 
ch.capture();

The following are the arguments in this feature.

ArgumentConditionDefinition
chargeRequired
amountOptionalThe amount to capture, which must be less than or equal to the original amount. Any additional amount will be automatically refunded.
application_feeOptionalAn application fee to add on to this charge. Can only be used with Stripe Connect.
receipt_emailOptionalThe email address to send this charge’s receipt to. This will override the previously-specified email address for this charge, if one was set. Receipts will not be sent in test mode.
statement_descriptorOptionalAn arbitrary string to be displayed on your customer’s credit card statement. This may be up to 22 characters. As an example, if your website is RunClub and the item you’re charging for is a race ticket, you may want to specify a statement_descriptor of RunClub 5K race ticket. The statement description may not include <>"' characters, and will appear on your customer’s statement in capital letters. Non-ASCII characters are automatically stripped. Updating this value will overwrite the previous statement descriptor of this charge. While most banks display this information consistently, some may display it incorrectly or not at all.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2";
ch = Charge.retrieve("ch_182TFv2eZvKYlo2Cjxtxxns4");
ch.capture();

Returns

Returns the charge object, with an updated captured property (set to true). Capturing a charge will always succeed, unless the charge is already refunded, expired, captured, or an invalid capture amount is specified, in which case this method will throw an error.

The following is an example response:

  com.stripe.model.Charge JSON: { 
"id": "ch_182TIR2eZvKYlo2CBtOAzEA8",
"object": "charge",
"amount": 4900,
"amount_refunded": 0,
"application_fee": null,
"balance_transaction": "txn_17bBwe2eZvKYlo2Cuwcyi9or", "captured": "true",
"created": 1461189343,
"currency": "usd",
"customer": "cus_8J5TWtg78fnA6G",
"description": "Charge for RelyMD consultation for 232311 23 21231231",
"destination": null,
"dispute": null,
"failure_code": null,
"failure_message": null,
"fraud_details": {
},
"invoice": null,
"livemode": false,
"metadata": {
},
"order": null,
"paid": true,
"receipt_email": null,
"receipt_number": null,
"refunded": false,
"refunds": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_182TIR2eZvKYlo2CBtOAzEA8/refunds "
},
"shipping": null,
"source": {
"id": "card_182TIQ2eZvKYlo2CQLZRW7uf",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8J5TWtg78fnA6G", "cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2018,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
},
"source_transfer": null,
"statement_descriptor": null, "status": "succeeded"
}

List all charges

Returns a list of charges you’ve previously created. The charges are returned in sorted order, with the most recent charges appearing first.

The following are the optional arguments in this feature.

ArgumentDefinition
createdA filter on the list based on the object created field. The value can be a string with an integer Unix timestamp, or it can be a dictionary with the other options.
customerOnly return charges for the customer specified by this customer ID.
ending_beforeA cursor for use in pagination. ending_before is an object ID that defines your place in the list. For example, if you make a list request and receive 100 objects, starting with obj_bar, your subsequent call can include ending_before=obj_bar in order to fetch the previous page of the list.
limitDefault is 10
sourceA filter on the list based on the source of the charge. The value can be a dictionary with the other options. Default is {object:”all”}
starting_afterA cursor for use in pagination. starting_after is an object ID that defines your place in the list. For example, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can include starting_after=obj_foo to fetch the next page of the list.

list-created

The following are the list-created object's optional timestamp child arguments.

ArgumentDefinition
gt(greater than) Return values where the created field is after this timestamp.
gte(greater than or equal) Return values where the created field is after or equal to this timestamp.
lt(less than) Return values where the created field is before this timestamp.
lte(less than or equal) Return values where the created field is before or equal to this timestamp.

list-source

The following is the list-source object's optional child argument.

ArgumentDefinition
objectReturn charges that match this source type string. Valid values are all, alipay_account, bitcoin_receiver, or card.

Returns

A dictionary with a data property that contains an array of up to limit charges, starting after charge starting_after. Each entry in the array is a separate charge object. If no more charges are available, the resulting array will be empty. If you provide a non-existent customer ID, this call raises an error.

You can optionally request that the response include the total count of all charges that match your filters. To do so, specify include[]=total_count in your request.

The following is an example response:

#<com.stripe.model.ChargeCollection id=#> JSON: { 
"data": [
com.stripe.model.Charge JSON: {
"id": "ch_182TXr2eZvKYlo2CL7W1pRX8",
"object": "charge",
"amount": 4900,
"amount_refunded": 0,
"application_fee": null,
"balance_transaction": "txn_17bBwe2eZvKYlo2Cuwcyi9or" ,
"captured": true,
"created": 1461190299,
"currency": "usd",
"customer": "cus_8J5jPkKzifsycT",
"description": "Premiere",
"destination": null,
"dispute": null,
"failure_code": null,
"failure_message": null,
"fraud_details": {
},
"invoice": null,
"livemode": false,
"metadata": {
},
"order": null,
"paid": true,
"receipt_email": null,
"receipt_number": null,
"refunded": false,
"refunds": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_182TXr2eZvKYlo2CL7W1pRX8/ref unds"
},
"shipping": null,
"source": {
"id": "card_182TXm2eZvKYlo2Cgun0fmfC",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8J5jPkKzifsycT", "cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2034,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": "sergio@willing.com",
"tokenization_method": null
},
"source_transfer": null,
"statement_descriptor": null,
"status": "succeeded"
},
#<com.stripe.model.Charge[...] ...>,
#<com.stripe.model.Charge[...] ...>
],
"has_more": false
}

Stripe's authentication API

· 18 min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Introduction

The Stripe authentication API is organized around REST. It has predictable, resource-oriented URLs, and uses HTTP response codes to indicate API errors. It uses built-in HTTP features, like HTTP authentication and HTTP verbs, which are understood by off-the-shelf HTTP clients. It supports cross-origin resource sharing, allowing you to interact securely with our API from a client-side web application (though you should never expose your secret API key in any public website’s client-side code).

To make the API as explorable as possible, accounts have test mode and live mode API keys. There is no “switch” for changing between modes, just use the appropriate key to perform a live or test transaction. Requests made with test mode credentials never hit the banking networks and incur no cost.

Authentication

Authenticate your account when using the API by including your secret API key in the request. You can manage your API keys in the Dashboard. Your API keys carry many privileges, so be sure to keep them secret! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth.

To use your API keys, assign it to Stripe.apiKey. The Python will then automatically send this key in each request.

All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.

The following is an example request. You can set the default API key, or you can always pass a key directly to an object’s constructor. Authentication is transparently handled for you in subsequent method calls.

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2";

Note: A sample test API key is included in all the examples on this page, so you can test any example right away. To test requests, using your account, replace the sample API key with your actual API key.

Errors

Stripe uses conventional HTTP response codes to indicate the success or failure of an API request. However, not all errors map cleanly onto HTTP response codes. When a request is valid but does not complete successfully (e.g., a card is declined), we return a 402 error code.

HTTP status code

The following table shows an HTTP status code summary:

Status CodeMeaning
200 - OKEverything worked as expected.
400 - Bad RequestThe request was unacceptable, often due to missing a required parameter.
401 - UnauthorizedNo valid API key provided.
402 - Request FailedThe parameters were valid but the request failed.
404 - Not FoundThe requested resource does not exist.
409 - ConflictThe request conflict with another request, perhaps due to using the same idempotent key.
429 - Too Many RequestsToo many requests hit the API too quickly.
500, 502, 503, 504 - Server ErrorsSomething went wrong on Stripe’s end. (These are rare.)

Error types

The following table shows the error types that you might come across:

Error TypeMeaning
api_connection_errorFailure to connect to Stripe’s API.
api_error API errors cover any other type of problem (e.g., a temporary problem with Stripe’s servers) and are extremely uncommon.
authentication-errorFailure to properly authenticate yourself in the request.
card_errorCard errors are the most common type of error you should expect to handle. They result when the user enters a card that cannot be charged for some reason.
invalid_request_errorInvalid request errors arise when your request has invalid parameters.
rate_limit_errorToo many requests hit the API too quickly.

Card errors

The following table shows the kind of card error that might occur:

Card ErrorMeaning
invalid_numberThe card number is not a valid credit card number.
invalid_expiry_monthThe card’s expiration month is invalid.
invalid_expiry_yearThe card’s expiration year is invalid.
invalid_cvcThe card’s security code is invalid.
incorrect_numberThe card number is incorrect.
expired_cardThe card has expired.
incorrect_cvcThe card’s security code is incorrect.
incorrect_zipThe card’s zip code failed validation.
card_declinedThe card was declined.
missingThere is no card on a customer that is being charged.
processing_errorAn error occurred while processing the card.

Note: CVC validation and zip validation can be enabled/disabled in your setting.

Handling errors

Our API libraries raise exceptions for many reasons, such as failed charge, invalid parameters, authentication errors, and network unavailability. We recommend writing code that gracefully handles all possible API exceptions as shown in the following example.

try { 
// Use Stripe's library to make requests...
} catch (CardException e) {

// Since it's a decline, CardException will be caught
System.out.println("Status is: " + e.getCode());
System.out.println("Message is: " + e.getMessage());
} catch (RateLimitException e) {

// Too many requests made to the API too quickly
} catch (InvalidRequestException e) {

// Invalid parameters were supplied to Stripe's API
} catch (AuthenticationException e) {

// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
} catch (APIConnectionException e) {

// Network communication with Stripe failed
} catch (StripeException e) {

// Display a very generic error to the user, and maybe send
// yourself an email
} catch (Exception e) {

// Something else happened, completely unrelated to Stripe
}

Idempotent requests

The API supports idempotency for safely retrying requests without accidentally performing the same operation twice. For example, if a request to create a charge fails due to a network connection error, you can retry the request with the same idempotency key to guarantee that only a single charge is created.

To perform an idempotent request, provide a key to setIdempotencyKey() on a request. It is completely up to you on how to create unique keys. We suggest using random strings or UUIDs. We will always send back the same response for requests made with the same key. However, you cannot use the same key with different request parameters. The keys expire after 24 hours.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Map<String, Object> chargeParams = new HashMap<String, Object>();
chargeParams.put("amount", 400);
chargeParams.put("currency", "usd");
chargeParams.put("source", "tok_182NNY2eZvKYlo2CRKti7ouM"); // obtained with Stripe.js
chargeParams.put("description", "Charge for test@example.co m");
RequestOptions options = RequestOptions
.builder()
.setIdempotencyKey("K3wYdmhSwv3qc1hi")
.build();

Charge.create(chargeParams, options);

Metadata

Metadata is useful for storing additional, structured information on an object. As an example, you could store your user’s full name and corresponding unique identifier from your system on a Stripe Customer object. Metadata is not used by Stripe (e.g., to authorize or decline a charge), and will not be seen by your users unless you choose to show it to them.

Some of the objects listed above also support a description parameter. You can use the description parameter to annotate a charge, for example, with a human-readable description, such as "2 shirts for test@example.com". Unlike metadata, description is a single string, and your users may see it (e.g., in email receipts Stripe sends on your behalf).

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2";

Map<String, Object> chargeParams = new HashMap<String, Obje ct>();
chargeParams.put("amount", 400);
chargeParams.put("currency", "usd");
chargeParams.put("source", "tok_182NNY2eZvKYlo2CRKti7ouM"); // obtained with Stripe.js
chargeParams.put("description", "Charge for test@example.co m");
Map<String, String> initialMetadata = new HashMap<String, S tring>();
initialMetadata.put("order_id", "6735");
chargeParams.put("metadata", initialMetadata); Charge.create(chargeParams);

The following is an example response:

com.stripe.model.Charge JSON: { 
"id": "ch_182Qxn2eZvKYlo2C24AvkVo2",
"object": "charge",
"amount": 360,
"amount_refunded": 0,
"application_fee": null,
"balance_transaction": "txn_17bBwe2eZvKYlo2Cuwcyi9or", "captured": true,
"created": 1461180375,
"currency": "usd",
"customer": null,
"description": "Guti Grewal (Siteset) - ggrewal@siteset.c o.uk - champagne",
"destination": null,
"dispute": null,
"failure_code": null,
"failure_message": null,
"fraud_details": {
},
"invoice": null,
"livemode": false,
"metadata": {
"order_id": "6735"
},
"order": null,
"paid": true,
"receipt_email": null,
"receipt_number": null,
"refunded": false,
"refunds": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/charges/ch_182Qxn2eZvKYlo2C24AvkVo2/refunds"
},
"shipping": null,
"source": {
"id": "card_182Qxm2eZvKYlo2CYk4giiM9", "object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": null,
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 11,
"exp_year": 2019,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
},
"source_transfer": null,
"statement_descriptor": null,
"status": "succeeded"
}

Note: You can have up to 20 keys, with key names up to 40 characters long and values up to 500 characters long.

The following details some common metadata use cases that you might come across:

Use caseDescription
Link IDsAttach your system’s unique IDs to a Stripe object for easy lookups. Add your order number to a charge, your user ID to a customer or recipient, or a unique recipient, or a unique receipt number to a transfer.
Refund papertrailsStore information about why a refund was created, and by whom.
Customer detailsAnnotate a customer by storing the customer’s phone number for your later use.

Pagination

All top-level API resources have support for bulk fetches via “list” API methods. For instance you can list charge, list customers, and list invoices. These list API methods share a common structure, taking at least these three parameters:

  • limit
  • starting_after
  • ending_before

Parameter usage:

  • Stripe utilizes cursor-based pagination via the starting_after and ending_before parameters.
  • Both take an existing object ID value (see below).
  • The ending_before parameter returns objects created before the named object, in descending chronological order.
  • The starting_after parameter returns objects created after the named object, in ascending chronological order.
  • If both parameters are provided, only ending_before is used.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 
Map<String, Object> customerParams = new HashMap<String, Ob ject>();
customerParams.put("limit", 3);
Customer.all(customerParams);

The following is an example response:

#<com.stripe.model.CustomerCollection id=#> JSON: { 
"data": [
com.stripe.model.Customer JSON: {
"id": "cus_8J34WqFQVUXoLz",
"object": "customer",
"account_balance": 0,
"business_vat_id": null,
"created": 1461180396,
"currency": "usd",
"default_source": "card_182QxV2eZvKYlo2CsBgeU8py", "delinquent": false,
"description": "James Harris",
"discount": null,
"email": "james.harris.43@example.com", "livemode": false,
"metadata": {
},
"shipping": null,
"sources": {
"object": "list",
"data": [
{
"id": "card_182QxV2eZvKYlo2CsBgeU8py", "object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8J34WqFQVUXoLz",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 12,
"exp_year": 2017,
"funding": "credit",
"last4": "4242",
"metadata": {
},
"name": null,
"tokenization_method": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/customers/cus_8J34WqFQVUXoLz/sources"
},
"subscriptions": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_8J34WqFQVUXoLz/subscripti ons"
}
},
#<com.stripe.model.Customer[...] ...>,
#<com.stripe.model.Customer[...] ...>
],
"has_more": false
}

The following table details some optional arguments that you will come across.

ArgumentDefinition
limitA limit on the number of objects to be returned, between 1 and 100.
starting_afterA cursor for use in pagination. starting_after is an object ID that defines your place in the list.
For example, if you make a list request and receive 100 objects, ending with obj_foo, your subsequent call can include starting_after=obj_foo in order to fetch the next page of the list.
ending_beforeA cursor for use in pagination. ending_before is an object ID that defines your place in the list.
For example, if you make a list request and receive 100 objects, starting obj_bar, your subsequent call can include ending_before=obj_bar in order to fetch the previous page of the list.

The following table details some response formats that you will come across.

FormatTypeDefinition
objectstring, value is “list”A string describing the object type returned.
dataarrayAn array containing the actual response elements, paginated by any request parameters.
has_morebooleanWhether or not there are more elements available after this set. If false, this set comprises the end of the list.
urlstringThe URL for accessing this list.

Auto-pagination

Most of our libraries support auto-pagination. This feature easily handles fetching large lists of resources without having to manually paginate results and perform subsequent requests.

To use the auto-pagination feature in Python, simply issue an initial “list” call with the parameters you need, then call auto_paging_iter() on the returned list object to iterate over all objects matching your initial parameters.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Map<String, Object> customerParams = new HashMap<String, Object>();
customerParams.put("limit", 3);

Iterable<Customers> itCustomers = Customer.list(planParams).autoPagingIterable();

for (Customer customer : itCustomers) {
// Do something with customer
}

Request IDs

Each API request has an associated request identifier. You can find this value in the response headers, under Request-Id. You can also find request identifiers in the URLs of individual request logs in your Dashboard.

Note: If you need to contact us about a specific request, providing the request identifier will ensure the fastest possible resolution.

Versioning

When we make backwards-incompatible changes to the API, we release new, dated versions. Read our API upgrades guide to see our API changelog and to learn more about backwards compatibility.

All request will use your account API settings, unless you override the API version. The changelog lists every available version. Note that events generated by aPI requests will always be structured according to your account API version.

The following is an example version request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 
Stripe.apiVersion = "2015-12-05";

To override the API version, assign the version to the stripe.api_version property.

You can visit your Dashboard to upgrade your API version.

Important: As a precaution, use API versioning to test a new API version before committing to an upgrade.

Balance

This is an object representing your Stripe balance. You can retrieve it to see the balance currently on your Stripe account.

You can also retrieve a list of the balance history, which contains a list of transactions that contributed to the balance (e.g., charges, transfers, and so forth).

The available and pending amounts for each currency are broken down further by payment source types.

balance object

The following table details all the attributes of the balance object.

AttributeTypeDefinition
objectstringThe value is balance.
availablearrayFunds that are available to be paid out automatically by Stripe or explicitly via the transfers API. The available balance for each currency and payment type can be found in the source_types property.
livemodebooleanThe default is false.
pendingarrayFunds that are not available in the balance yet, due to the 7-day rolling pay cycle. The pending balance for each currency and payment type can be found in the source_types property.

The following is an example response:

com.stripe.model.Balance JSON: { 
"object": "balance",
"available": [
{
"currency": "usd",
"amount": 8045591482,
"source_types": {
"card": 8035133499,
"bank_account": 9008784,
"bitcoin_receiver": 1449199
}
}
],
"livemode": false,
"pending": [
{
"currency": "usd",
"amount": 1097295875,
"source_types": {
"card": 1097295875,
"bank_account": 0,
"bitcoin_receiver": 0
}
}
]
}

balance_transaction

The following table details all the attributes of the balance_transaction object:

AttributeTypeDefinition
idstringThe unique ID.
objectstringThe value is balance_transaction
amountintegerGross amount of the transaction, in cents.
available_ontimestampThe date the transaction in net funds will become available in the Stripe balance.
createdtimestampDate created
currencycurrencyThe currency used
descriptionstringMemo field for any remarks
feeintegerFees (in cents) paid for ttransaction.
fee_detailslistDetailed breakdown of fees (in cents) paid for this transaction.
netintegerNet amount of the transaction, in cents.
sourcestringThe Stripe object this transaction is related to.
`sourced_transferlistThe transfers (if any) for which source is a source_transaction
statusstringIf the transaction’s net funds are available in the Stripe balance yet. Valid values are available or pending.
typestringTransaction type valid values:
adjustment
application_fee
application_fee_refuncharge
payment
payment_refund
refuntransfer
transfer_cancel
transfer_failure
transfer_refund

fee_details

The following are the fee_details child attributes:

AttributeTypeDefinition
amountinteger
applicationstring
currencycurrency
descriptionstring
typestringType of the fee, one of: application_fee, stripe_fee or tax.

sourced_transfer

The following are the sourced_transfer child attributes:

AttributeTypeDefinition
objectstringThe value is list.
dataarrayContains: transfer and object
has_morebooleanThe default is false
total_count positive integer or zeroThe total number of items available. This value is not included by default, but you can request it by specifying
?include[]=total_count
urlstringThe URL where this list can be accessed.

The following is an example response:

com.stripe.model.BalanceTransaction JSON: { 
"id": "txn_17bBwe2eZvKYlo2Cuwcyi9or",
"object": "balance_transaction",
"amount": 400,
"available_on": 1455235200,
"created": 1454687788,
"currency": "usd",
"description": "Charge for test@example.com", "fee": 42,
"fee_details": [
{
"amount": 42,
"application": null,
"currency": "usd",
"description": "Stripe processing fees",
"type": "stripe_fee"
}
],
"net": 358,
"source": "ch_17bBwe2eZvKYlo2Crk3VGEG8",
"sourced_transfers": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/transfers?source_transaction=ch_17bBwe2eZvK Ylo2Crk3VGEG8"
},
"status": "pending",
"type": "charge"
}

Retrieve balance

Retrieves the current account balance, based on the authentication that was used to make the request.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 
Balance.retrieve();

Returns

Returns a balance object for the account authenticated as.

The following is an example response:

com.stripe.model.Balance JSON: { 
"object": "balance",
"available": [
{
"currency": "usd",
"amount": 8045591482,
"source_types": {
"card": 8035133499,
"bank_account": 9008784,
"bitcoin_receiver": 1449199
}
}
],
"livemode": false,
"pending": [
{
"currency": "usd",
"amount": 1097295875,
"source_types": {
"card": 1097295875,
"bank_account": 0,
"bitcoin_receiver": 0
}
}
]
}

Retrieve a balance transaction

Retrieves the balance transaction with the given ID.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2";
BalanceTransaction.retrieve("txn_17bBwe2eZvKYlo2Cuwcyi9or") ;

Returns

Returns a balance transaction if a valid balance transaction ID was provided. Raises an error otherwise.

The following is an example response:

com.stripe.model.BalanceTransaction JSON: { 
"id": "txn_17bBwe2eZvKYlo2Cuwcyi9or",
"object": "balance_transaction",
"amount": 400,
"available_on": 1455235200,
"created": 1454687788,
"currency": "usd",
"description": "Charge for test@example.com",
"fee": 42,
"fee_details": [
{
"amount": 42,
"application": null,
"currency": "usd",
"description": "Stripe processing fees",
"type": "stripe_fee"
}
],
"net": 358,
"source": "ch_17bBwe2eZvKYlo2Crk3VGEG8",
"sourced_transfers": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/transfers?source_transaction=ch_17bBwe2eZvK Ylo2Crk3VGEG8"
},
"status": "pending",
"type": "charge"
}

List all balance history

Returns a list of transactions that have contributed to the Stripe account balance (e.g., charges, transfers, and so forth). The transactions are returned in sorted order, with the most recent transactions appearing first.

To do so, simply add BalanceTransaction.all(); to your program.

The following table details all the optional attributes involved in this feature:

AttributeDefinition
available_onA filter on the list based on the object available_on field. The value can be a string with an integer Unix timestamp, or it can be a dictionary with other options. (see the Note below)
createdA filter on the list based on the object created field. The value can be a string with an integer Unix timestamp, or it can be a dictionary with other options. (see the Note below)
currencyThe currency used.
ending_beforeA cursor for use in pagination. ending_before is an object ID that defines your place in the list.
For example, if you make a list request and receive 100 objects, starting with obj_bar, your subsequent call can include ending_before=obj_bar in order to fetch the previous page of the list.
limitThe default is 10. A limit on the number of objects to be returned. Limit can range between 1 and 100 items.
sourceOnly returns the original transaction.
starting_afterA cursor for use in pagination. starting_after is an object ID that defines your place in the list.
For example, if you make a list request and receive 100 objects, starting with obj_foo, your subsequent call can include starting_after=obj_foo to fetch the next page of the list.
transferFor automatic Stripe transfers only, only returns transactions out on the specified transfer ID.
typeOnly returns transactions of the given type. One of:
charge
refund
adjustment
application_fee
application_fee_refund
transfer
transfer_failure

available_on

The following are the available_on optional child timestamp attributes.

AttributeDefinition
gt(greater than) Return values where the available_on field is after this timestamp.
gte(greater than or equal) Return values where the available_on field is after or equal to this timestamp.
lt(less than) Return values where the available_on field is before this timestamp.
lte(less than or equal) Return values where the available_on field is before or equal to this timestamp.

created

The following are the created optional child timestamp attributes.

AttributeDefinition
gt(greater than) Return values where the created field is after this timestamp.
gte(greater than or equal) Return values where the created field is after or equal to this timestamp.
lt(less than) Return values where the created field is before this timestamp.
lte(less than or equal) Return values where the created field is before or equal to this timestamp.

The following is an example request:

Stripe.apiKey = "test_BQokikJOvBiI2HlWgH4olfQ2"; 

Map<String, Object> balanceTransactionParams = new HashMap< String, Object>();
balanceTransactionParams.put("limit", 3);

Balancetransaction.all(balanceTransactionParams);

Returns

A dictionary with a data property that contains an array of up to limit transactions, starting after transaction starting_after. Each entry in the array is a separate transaction history object. If no more transactions are available, the resulting array will be empty.

You can optionally request that the response include the total count of all transactions that match your filters. To do so, specify include[]=total_count in your request.

The following is an example response:

#<com.stripe.model.BalanceTransactionCollection id=#> JSON: { 
"data": [
com.stripe.model.BalanceTransaction JSON: {
"id": "txn_17bBwe2eZvKYlo2Cuwcyi9or",
"object": "balance_transaction",
"amount": 400,
"available_on": 1455235200,
"created": 1454687788,
"currency": "usd",
"description": "Charge for test@example.com", "fee": 42,
"fee_details": [
{
"amount": 42,
"application": null,
"currency": "usd",
"description": "Stripe processing fees",
"type": "stripe_fee"
}
],
"net": 358,
"source": "ch_17bBwe2eZvKYlo2Crk3VGEG8",
"sourced_transfers": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/transfers?source_transaction=ch_17bBwe2 eZvKYlo2Crk3VGEG8"
},
"status": "pending",
"type": "charge"
},
#<com.stripe.model.BalanceTransaction[...] ...>,
#<com.stripe.model.BalanceTransaction[...] ...>
],
"has_more": false
}

KB - AppStack not excluded from Writables

· One min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Symptoms

Exclusions added to AppStack snapvol.cfg files are not excluded from Writables Volumes.

Writable Volumes still capture files that could be excluded in AppStack snapvol.cfg files. This could cause potential conflicts and unexpected behaviors.

Resolution

These symptoms are caused because writable policy affects the whole system while AppStack policy affects only AppStacks.

Since AppStack exclusions will not apply to a writable, those exclusions need to be listed in snapvol.cfg files in order to prevent core applications and services from being broken. So, it’s necessary to list the same exclusions in both AppStacks AND writable snapvol.cfg files when attaching a writable.

To exclude a location, edit the snapvol.cfg file to add the full path that is to be excluded. Paths can be listed in any order, for example:

# File system exclusions

exclude_path=\ProgramData\ntuser.pol
exclude_path=\ProgramData\tempntuser.pol
exclude_path=\ProgramData\VMware

For more information about the snapvol.cfg file, see http://blogs.vmware.com/euc/2016/03/app-volumes-snapvol-cfg-writable-volume-customize-configure.html.

Note: Introducing a writable volume without the explicit exclusions added, re-breaks the same core apps and services. Re-adding the exclusions to the writable via the zip file method fixes this.

KB - AppStacks disabled after rescan

· One min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Symptoms

After running an AppStack rescan, you experience one of these symptoms:

  • AppStacks appears as disabled
  • AppStacks appears as unprovisioned in the manager UI

Cause

This issue occurs because a separate AppVolumes deployment is configured to use the same datastore, which is not supported.

AppVolumes modifies the metadata of AppStacks, especially in version 3.0. When rescanning, the system reads the metadata of the AppStacks on the datastore and reflects the changes in the UI.

Resolution

To resolve this issue, change the configuration of the second AppVolumes deployment to point to another path on the datastore, use another datastore, or stop the service/server.

To prevent this issue from recurring, move the AppStacks on the production datastore to a different path on the datastore, import them, and recreate the assignments.

KB - Writables not created

· 2 min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Part of the writables are not created upon login in a multi-vCenter environment

Symptoms

AppVolumes 2.11 and above is configured to work with more than one vCenter.

Writables are created for an AD group and the writable creation is delayed until login time.

When logging in to VMs in one of the vCenters with a user which is part of the AD group, a writable is created for that user.

When logging in to a VM on another vCenter, a writable is NOT created for the user, and no writable is attached to the user.

The following log can be found in the Manager log corresponding to the login attempt:

DEBUG Cvo: Culling "DOMAIN\GROUP" because it does not have files accessible to the machine manager running "Computer <DOMAIN\MACHINE$>"

Cause

When creating a writable volume for a group account, a writable volume is actually created for the group account, not a single user. Then this writable will be used as a source template for the direct writables which will be created for the users in the group.

When a user logs in, this writable is cloned.

Only one copy of the group writable is created on one of the vCenters that accepted the job and started the writable creation task.

Logging into a VM:

  • on the same vCenter will create the writable successfully.
  • on another vCenter will not create the writable, as this file is not accessible from another vCenter.

Resolution

Storage used for the writable volumes should be common between vCenters, otherwise logging in to different vCenters will result in different writables splitting user data between separate VMDKs.

You need to follow these steps to import the group writable entry from the other vCenter:

  1. Open the writable volumes screen by clicking Volumes > Writables
  2. Click on Import Writables
  3. Choose the common writables datastore related to the vCenter which is not able to create the writable volumes.
  4. Click on the Import button and wait for the writables to be imported. Note: Each writable will have a separate record for each vCenter.
  5. Log into a VM on the other vCenter. That will automatically create the writable using the group writable record for this vCenter.

Important: Do not forget to perform this import operation after all writables are created!

Note: Each writable must have as many records as the number of vCenters

KB - Log collection usage

· 3 min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

This KB describes how to install and use Log Collection with App Volumes.

Introduction

Currently, no method exists to collect Agent and Manager logs to a central location.

With the log collector, every agent and manager will periodically push their log files to a fileshare.

To start collecting logs, every Agent and Manager will call a .bat file depending on the bit version:

  • 32-bit: C:\Program Files (x86)\CloudVolumes\DctLogCollector\support.bat
  • 64-bit: C:\Program Files\CloudVolumes\DctLogCollector\support.bat

The Agent and Manager are configured to periodically push the log files to a fileshare; but if you need to manually collect logs, running the .bat file alone would also push log files to the fileshare.

Configuration of the Log Fileshare

To make the Agent and Manager aware of the fileshare, configure the Log Fileshare in the following way.

To create a Log Fileshare, go to http://localhost/log_fileshares/new and input the following Log Fileshare fields:

FieldDescription
Host nameThis is host and folder name for your Log Fileshare.
For example, \\10.33.99.231\uem\logs
Make sure your path ends with a logs folder.
UsernameUsername of the Log Fileshare
PasswordPassword of the Log Fileshare
DomainDomain of the Log Fileshare
Agent TimeThe agent will periodically push log files to the fileshare. This parameter sets how much time delay is required. Time is denoted in minutes.

Other Fileshare actions

Fileshare actionGo to
Edithttp://localhost/log_fileshares/edit
View or deletehttp://localhost/log_fileshares

Note: Every setup can have only one Log Fileshare.

Agent log collection

The Agent will request for the Log Fileshare credentials by sending a GET request to:

<manager’s ip address>/log_fileshares/active

After the Agent gets these details, the Agent will run the log collector periodically, based on the time configured.

Note: While the collection is running, the user’s desktop CPU usage will spike until the collection ends.

Note: The tool’s performance has not yet been tested and validated at large scale.

Manager log collection

The Manager has a ruby job running called collect_logs which will periodically call the support.bat file with the required parameters.

To configure the time for the manager to collect logs, change the duration in the clock.yml file. The Manager logs are collected every 12 hours.

Switching off log collection

You can deactivate log collection by unchecking the Is active checkbox in the Log Fileshare configuration page.

Running batch scripts on Agents and Managers

In Windows, no setup is required. The .bat script is shipped with the Agent and Manager images. In order to collect Agent logs, make sure https is enabled; otherwise, this feature will be turned off in the Agent.

Note: The .bat script needs administration privileges to run.

The .bat script can be run from:

C:\Program Files (x86)\CloudVolumes\DctLogCollector\support.bat

The following are the parameters for support.bat:

ParameterDescription
-destinationDestination of the log files on the machine
-fhhostLocation of the folder on hostname of the fileshare.
For example, \\xx.xx.xx.xx\logs
(Make sure the folder named logs exists)
-fhunameUsername of the fileshare owner
-fhdomainDomain under which the fileshare is located
-fhpwdPassword of the username for the fileshare owner

Example of running the script:

support.bat -destination C:\Logs -fhhost \\10.33.99.231\uem\logs -fhdomain <domain> -fhuname <username> -fhpwd <password>

KB - Printers with ThinPrint conflicts

· One min read
Guy Klages
Ex-Meta Technical Writer, Co-founder FindFit

Symptoms

At logon, printers are recreated, but the default printer is not being retained at each login. Also printers set to Default by UEM are not the Default anymore.

Users have to manually set their default printer again.

The user is connecting through VMware View or Horizon client from a PC or Thin Client.

Cause

This is caused by ThinPrint default printer redirection.

Default behavior of ThinPrint is to redirect the default local printer to the user session. This overwrites the default printer setting from the session.

Resolution

This can be solved by changing the behavior of ThinPrint.

You have three options:

OptionDescription
ADisable the default ThinPrint printer redirection completely in View Clients, detailed at https://kb.vmware.com/kb/2012770
BDisable only the default ThinPrint printer on a VMware View Client, detailed at https://kb.vmware.com/kb/2003626
CUse the View ADM template to disable printer redirection.
Use the view client adm template (vdm_client.adm) by adding the template to an existing or new GPO.
Under user configuration > administrative templates > VMware View Client Configuration/RDP settings, select Disable redirect printers.