I created the Stripe plugin for Corona SDK to give Corona developers an easy way to accept online payments from inside their apps with as little as a single line of code.
This page contains the documentation for the plugin, as well as a sample project you can download and run to see the plugin in action for yourself. Please check back, as I will continue to update this page whenever bug fixes or new features are added.
Table of Contents
- Change Log
- About Stripe
- Stripe Account Setup
- Adding the Plugin to Your App
- Initializing the Plugin
- Single Line of Code? Prove It!
- Syntax and Usage
- Stripe Objects
- Plugin Functions
- Gotchas
- Demo Project
Change Log
- 2/22/2016 : Initial public release.
About Stripe
Stripe is a startup that allows private individuals and businesses to accept online payments on websites and apps. They are a competitor to businesses like PayPal, and since being founded in 2010 they have grown at a rapid pace to become a major player in the mobile payments arena. If you regularly make online purchases, there’s a good chance that you’ve had your money move through their servers at some point. The bottom line is that Stripe makes it possible for you to securely accept payments in your app with Stripe doing most of the heavy lifting. I am a fan of their clean and easy-to-understand API, and the fact that they accept all sorts of payment types, from credit cards to Bitcoin.
I am in no way affiliated with Stripe, and they had nothing to do with the creation of this plugin. I’m just a fan of their API and thought it would be a useful tool for the Corona community – that’s why I built it.
Fees
-
Like all online payment processors, Stripe takes a percentage of each transaction to cover their costs and earn profit. This is not unlike Apple and Google Play’s 30% commission on app sales. As of February 2016, Stripe charges 2.9% plus 30 cents (USD) per successful charge, with lower rates in certain circumstances for European customers. There are no setup or monthly fees – they only collect a fee when you accept a payment. For the most up-to-date details on Stripe’s pricing structure, please visit stripe.com/pricing.
Please know that there is no usage fee associated with the Stripe plugin for Corona SDK – while I may charge a one-time fee for buying the plugin in the future, I make absolutely zero dollars from transactions processed using the plugin. Any fees that are collected are collected by Stripe, and the rates are set at Stripe’s discretion. Fortunately, the Stripe dashboard makes it easy to view the status of your account, along with any fees incurred, at a glance.
The Stripe API
-
While I designed this plugin to make it easy to use the Stripe API in your app, it would still behoove you to spend some time exploring Stripe’s easy-to-understand API Reference guide. This page should provide enough information to use the plugin on a basic level, but if you really want to make the most of Stripe’s functionality, I strongly advise you spend some time reading up on their API.
As you read up on the Stripe API, you may notice that there are endpoints and functions in the API that are not accounted for in the plugin. That’s because there are certain functionalities, such as processing refunds, that are simply better handled via the Stripe dashboard in my opinion. That said, there’s no technical reason why the plugin couldn’t be expanded to include features that are currently missing. If you have a particular need to access additional endpoints using the plugin, let me know and I’ll consider making additions. But I’m confident that almost every conceivable use for Stripe in a Corona app can be achieved with the current plugin capabilities.
Stripe Account Setup
Before you can use the Stripe plugin, you need to set up a free account with Stripe and obtain your account’s “API keys.” These keys are string values that ensure that charges made in your app are deposited into your Stripe account. Here’s a quick primer on setting up a new Stripe account and obtaining your keys (it only takes a minute or two):
- Go to stripe.com and click the “sign up” button. (If you already have a Stripe account, just sign in and skip ahead to step 3.)
- Enter in your email address and choose a password, then click the “create your Stripe account” button to create your account and go to your Stripe dashboard.
- Once you are on your Stripe dashboard, go to your account settings and choose the “API Keys” option. You’ll see two sets of keys: a “test” set and a “live” set. You can only use one set of keys at a time (test or live) with the Stripe plugin. It’s best to use your test keys while you are developing your app to prevent accidental “real world” charges, but be sure to use the live keys on the version you release, or else you won’t actually get paid for any charges made in your app.
Adding the Plugin to Your App
Before you can require the plugin for use in your app, you’ll need to do two things:
- Activate the plugin for your Corona developer account at store.coronalabs.com
- Add an entry into a plugins table of your build.settings. The following is an example of a minimal build.settings file with the required entry for the Stripe plugin:
settings = { plugins = { -- @schroederapps' Stripe plugin: ["plugin.stripe"] = { publisherId = "com.jasonschroeder", }, }, }
After you’ve taken the above steps, you can require the plugin in your app with just one line of code:
local stripe = require("plugin.stripe")
Initializing the Plugin
Now that you have your Stripe account’s API keys handy, call stripe.init() in your code, preferably just after requiring the plugin. stripe.init() requires a single argument: a table with two key-value pairs. In this table, “secretKey” is a string containing your Stripe account’s secret API key, and “publishableKey” is a string containing your Stripe account’s publishable key. You can use either test or live keys, depending on your needs, but make sure that the keys you input are both from the same set (test or live). Your code should look something like this:
local stripe = require("plugin.stripe") stripe.init({ secretKey = "sk_test_abc123", publishableKey = "pk_test_abc123" }) -- replace these keys with your test or live Stripe API keys
IMPORTANT!!! Be sure to NEVER use your live keys unless you are ready to accept real-world charges. Likewise, never user your test keys in an app that you are releasing for real-world usage. Calling stripe.init() with the wrong set of keys makes the difference between getting paid in real or pretend dollars – so proceed carefully!
Single Line of Code? Prove It!
There is a lot of functionality in the Stripe plugin, and it can get a little complicated to access every nook and cranny. But I want to show you a basic, minimum main.lua that would create a charge in as little code as possible. The code below, if you enter in valid API keys, will prompt the user to pay you $1.00 – and it’s for real! If you use live API keys, that $1.00 will actually make its way to your real-life bank account. It’s that easy!
local stripe = require("plugin.stripe") stripe.init({ secretKey = "sk_test_ABC123", publishableKey = "pk_test_ABC123" }) stripe.checkout({amount = 100, currency = "usd"})
Syntax & Usage
All of the functions in the Stripe plugin are designed to have a common syntax. Toward that end, each function only accepts a single Lua table as the sole argument, which I refer to as params in the documentation. The properties of that table will vary depending on the function being called, but there are two specific key/value pairs that you should always include in your params table: an onSuccess function and an onFail function.
onSuccess Functions
-
Every params table should include an onSuccess property that points to a function to be called after a successful request to Stripe’s servers. An onSuccess function can optionally accept two two Lua tables as arguments. The first argument will always take the form of a Stripe object Lua table (more on that below). The second is a standard Corona networkRequest event table with details on the Stripe API request.
onFail Functions
-
Every params table should also include an onFail property that points to a function to be called if the request to Stripe’s servers fails. Request failure could be because of a network connection issue, or because Stripe’s servers reported an error (for example, if you attempted to charge an invalid or expired credit card). An onFail function can optionally accept one argument: a standard Corona networkRequest event table. (If your request was rejected by Stripe, details on the cause of the rejection will be found in event.response, a JSON string that you can convert into a Lua table using Corona’s built-in JSON library.)
The below sample requests details on a Stripe charge with the ID ch_17dAujELWHyjUdjW854zZ7yR using stripe.getCharge(). If the request is successful, the onSuccess function will print the amount of the charge to the terminal as well as the currency. If the request is unsuccessful, the onFail function will print details on the failed request to the terminal:
local function _onSuccess(charge, event) print("stripe.getCharge() succeeded!") print("Amount: " .. charge.amount .. " " .. charge.currency) end local function _onFail(event) print("stripe.getCharge() failed!") for k,v in pairs(event) do print(k, v) end end stripe.getCharge({ charge = "ch_17dAujELWHyjUdjW854zZ7yR", onSuccess = _onSuccess, onFail = _onFail, })
Stripe Objects
When you make a successful API call to Stripe’s servers via the plugin, a Stripe “object” is always returned to your onSuccess function. These objects contain data about the successful transaction and always take one of three forms: Charges, Customers, or Tokens.
Charges
-
Charge objects are tables containing complete details on any successful charge attempt on your Stripe account. Calling stripe.checkout() or stripe.newCharge() creates a new charge object, while other functions like stripe.getCharge() retrieve or manipulate an existing charge. The most important property of a charge object is the “id” string, which is a unique identifier for the object. For a complete list of charge object properties, please visit Stripe’s API Reference docs.
Here is an example of a charge object table that might be returned after calling stripe.newCharge():
{ id = "ch_17g5qRELWHyjUdjWPM4TudYU", object = "charge", amount = 50, amount_refunded = 0, balance_transaction = "txn_17fwVZELWHyjUdjWnsgnZzZF", captured = true, created = 1455855979, currency = "usd", fraud_details = {}, livemode = false, metadata = {}, paid = true, refunded = false, refunds = { object = "list", data = {}, has_more = false, total_count = 0, url = "/v1/charges/ch_17g5qRELWHyjUdjWPM4TudYU/refunds" }, source = { id = "card_17g5qRELWHyjUdjWnmOFzst8", object = "card", brand = "Visa", country = "US", cvc_check = "pass", exp_month = 1, exp_year = 2020, funding = "credit", last4 = "4242", metadata = {}, }, status = "succeeded" }
The following plugin functions return charge objects to their onSuccess functions:
- stripe.checkout()
- stripe.newCharge()
- stripe.getCharge()
- stripe.updateCharge()
- stripe.captureCharge()
- stripe.listCharges()
- stripe.donate()
Customers
-
Customer objects are tables containing complete details on a customer record in your Stripe account. Calling stripe.newCustomer() creates a new customer object, while other functions like stripe.updateCustomer() retrieve or manipulate an existing customer record. The most important property of a customer object is the “id” string, which is a unique identifier for the object. For a complete list of customer object properties, please visit Stripe’s API Reference docs.
Here is an example of a customer object table that might be returned after calling stripe.newCustomer():
{ id = "cus_7uoSw2DHrv47t8", object = "customer", account_balance = 0, created = 1455590661, currency = "usd", delinquent = false, livemode = false, metadata = {}, sources = { object = "list", data = {}, has_more = false, total_count = 0, url = "/v1/customers/cus_7uoSw2DHrv47t8/sources" }, subscriptions = { object = "list", data = {}, has_more = false, total_count = 0, url = "/v1/customers/cus_7uoSw2DHrv47t8/subscriptions" } }
The following plugin functions return customer objects to their onSuccess functions:
- stripe.newCustomer()
- stripe.getCustomer()
- stripe.updateCustomer()
- stripe.deleteCustomer()
- stripe.listCustomers()
Tokens
-
Stripe tokens are objects that can be used anywhere in the Stripe API that a card or bank account is accepted, allowing you to charge a card without knowing the card numbers. Note that tokens are not meant to be stored or used more than once — you cannot make multiple charges using the same token. Calling newToken() creates a new token object, while stripe.getToken() retrieves an existing token object. The most important property of a token object is the “id” string, which is a unique identifier for the object. For a complete list of token object properties, please visit Stripe’s API Reference docs.
Here is an example of a token object table that might be returned after calling stripe.newToken():
{ id = "tok_17g5VNELWHyjUdjWdaoe160q", object = "token", card = { id = "card_17g5VNELWHyjUdjWTI97Qd3H", object = "card", brand = "Visa", country = "US", exp_month = 8, exp_year = 2017, funding = "credit", last4 = "4242", metadata = {}, }, created = 1455854673, livemode = false, type = "card", used = false }
The following plugin functions return token objects to their onSuccess functions:
* stripe.checkout() only returns a token if you specify chargeNow = false in the params table. Otherwise, the card is charged and a charge object is returned instead.
Plugin Functions
stripe.checkout(params)*
*NOTE: currently stripe.checkout() is only available on Mac OS X and iOS because of limitations with how Corona SDK handles webViews and stripe’s Checkout javascript template. I hope to add support for Android soon. But you can achieve the same functionality using a combination of stripe.newToken() and stripe.newCharge() – you’d just need to build your own form for collecting credit card data.
-
Description:
- amount: (required) an integer representing the amount to be charged, in the lowest currency unit.
- currency: (required) a string representing the 3-character ISO for the currency to be charged (What currencies does Stripe support?)
- description: (optional, but strongly suggested) An arbitrary string which you can attach to a charge object. 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.
- chargeNow: (boolean)(optional) Whether or not to process the charge immediately upon the user completing the Checkout form. Defaults to true.
- data: (optional, but strongly suggested) a table containing key/value pairs that correspond to the configuration options listed in Stripe’s Checkout documentation. Here are the available key/value pairs:
- image: A relative or absolute URL pointing to a square image of your brand or product. The recommended minimum size is 128x128px. The recommended image types are .gif, .jpeg, and .png.
- name: The name of your company or website.
- description: A description of the product or service being purchased. Defaults to the description specified in your params table.
- amount: The amount (in cents) that’s shown to the user on the Checkout form. Default to the charge amount specified in your params table.
- locale: The language to used in the Checkout form. Defaults to the user’s preferred language, if available, or English if not available.
- currency: The currency of the amount (3-letter ISO code). Defaults to the currency specified in your params table.
- panel-label: The label of the payment button in the Checkout form (e.g. “Subscribe”, “Pay {{amount}}”, etc.). If you include {{amount}}, it will be replaced by the provided amount. Otherwise, the amount will be appended to the end of your label. Checkout does not translate custom labels to the user’s preferred language.
- zip-code: Specify whether Checkout should validate the billing ZIP code (true or false). The default is false.
- billing-address: Specify whether Checkout should collect the user’s billing address (true or false). The default is false.
- shipping-address: Specify whether Checkout should collect the user’s shipping address (true or false). The default is false.
- email: If you already know the email address of your user, you can provide it to Checkout to be pre-filled.
- bitcoin: Specify whether to accept Bitcoin (true or false). The default is false.
- alipay: Specify whether to accept Alipay (‘auto’, true, or false). The default is false.
- alipay-reusable: Specify if you need reusable access to the customer’s Alipay account (true or false). The default is false.
- capture: (boolean)(optional) Whether or not to immediately capture the charge. Defaults to true. When false, the charge issues an authorization (or pre-authorization), and will need to be captured later. Uncaptured charges expire in 7 days. For more information, see authorizing charges and settling later.
- metadata: (optional) an A table 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.
- receipt_email: (optional) A string representing the email address to send this charge’s receipt to. The receipt will not be sent until the charge is paid. 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.
- statement_descriptor: (optional) An 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.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
- onCancel: (optional, but strongly suggested) a function triggered when a user manually closes the Checkout form without completing the checkout process.
Displays a Stripe Checkout payment form and makes a new charge immediately. This is a two-step process. First, a token is created for the payment method entered by the user, and then a charge is created using that token. (You can elect to skip the second step and only create a token if you wish.) This is the easiest way to process a charge using the Stripe plugin, as it handles collecting customer data for you, securely using Stripe’s servers. See stripe.com/checkout for more details on the Stripe Checkout platform.
Arguments:
stripe.checkout() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s Checkout documentation for more details.
Returns:
A Stripe charge object to your onSuccess listener if you elect to process the charge immediately (this is the default behavior). If you specify chargeNow = false in your params table, a Stripe token object will be returned to your onSuccess function instead. A Corona networkRequest table to your onFail listener in an error occurs.
Sample Code:
stripe.checkout({ amount = "500", currency = "usd", description = "stripe.checkout()", onSuccess = _onSuccess, onFail = _onFail, onCancel = _onCancel, data = { image = "https://www.jasonschroeder.com/wp-content/uploads/2016/02/stripe_icon.png", name = "Stripe Plugin for Corona SDK", locale = "auto", ["zip-code"] = true, }, chargeNow = true, })
stripe.newCharge(params)
-
Description:
- amount: (number)(required) a positive integer representing the amount to be charged, in the lowest currency unit. The minimum amount is $0.50 (or equivalent in charge currency).
- currency: (string)(required) a 3-letter ISO code for currency.
- source: (string or table)(either source or customer is required) A 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 (string), or a table containing a user’s credit card details, with the options described below. Although not all information is required, the extra info helps prevent fraud.
- exp_month: (string)(required) Two digit number representing the card’s expiration month.
- exp_year: (string)(required) Two or four digit number representing the card’s expiration year.
- number: (string)(required) The card number, as a string without any separators.
- object: (string)(required) The type of payment source. Should be “card”.
- cvc: (string)(required) Card security code.
- address_city (optional)
- address_country (optional)
- address_line1 (optional)
- address_line2 (optional)
- name: Cardholder’s full name (optional)
- address_state (optional)
- address_zip (optional)
- customer: (string)(either source or customer is required) The ID of an existing customer that will be charged in this request.
- capture: (boolean)(optional) Whether or not to immediately capture the charge. Defaults to true. When false, the charge issues an authorization (or pre-authorization), and will need to be captured later. Uncaptured charges expire in 7 days. For more information, see authorizing charges and settling later.
- description: (optional, but strongly suggested) An arbitrary string which you can attach to a charge object. 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.
- metadata: (optional) an A table 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.
- receipt_email: (optional) A string representing the email address to send this charge’s receipt to. The receipt will not be sent until the charge is paid. 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.
- statement_descriptor: (optional) An 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.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Charges a Stripe customer ID, Stripe token or credit/debit card for a specified amount.
Arguments:
stripe.checkout() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s create a charge documentation for more details.
Returns:
A Stripe charge object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
-- card #s as source: stripe.newCharge({ amount = 50, currency = "usd", source = { exp_month = "01", exp_year = "20", number = "4242424242424242", object = "card", cvc = "123", }, onSuccess = _onSuccess, onFail = _onFail, }) -- Stripe token as source: stripe.newCharge({ amount = 50, currency = "usd", source = "tok_17g5VNELWHyjUdjWdaoe160q", onSuccess = _onSuccess, onFail = _onFail, })
stripe.getCharge(params)
-
Description:
- charge: (string)(required) The identifier of the charge to be retrieved.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Retrieves an existing charge from Stripe’s servers.
Arguments:
stripe.getCharge() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s retrieve a charge documentation for more details.
Returns:
A Stripe charge object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.getCharge({ charge = "ch_17hB05ELWHyjUdjWfl5TvfPG", onSuccess = _onSuccess, onFail = _onFail, })
stripe.updateCharge(params)
-
Description:
- charge: (string)(required) The identifier of the charge to be updated.
- description: (string)(optional) An 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.
- fraud_details: (table)(optional) A 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.
- metadata: (table)(optional) A 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.
- receipt_email: (string)(optional) This 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.
- shipping: (table)(optional) Shipping information for the charge. Helps prevent fraud on charges for physical goods.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Adds or edits data for an existing charge on Stripe’s servers.
Arguments:
stripe.updateCharge() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s update a charge documentation for more details.
Returns:
The updated Stripe charge object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.updateCharge({ charge = "ch_17hB05ELWHyjUdjWfl5TvfPG", description = "description updated!", metadata = { foo = "bar", whoLetTheDogsOut = "who. who. who. who.", knowing = "half the battle.", }, onSuccess = _onSuccess, onFail = _onFail, })
stripe.captureCharge(params)
-
Description:
- charge: (string)(required) The identifier of the charge to be captured.
- amount: (integer)(optional) The amount to capture, which must be less than or equal to the original amount. Any additional amount will be automatically refunded.
- receipt_email: (string)(optional) The 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_descriptor: (string)(optional) An arbitrary string to be displayed on your customer’s credit card statement. This may be up to 22 characters.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
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.
Arguments:
stripe.captureCharge() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s capture a charge documentation for more details.
Returns:
The newly-captured Stripe charge object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.captureCharge({ charge = "ch_17hB05ELWHyjUdjWfl5TvfPG", onSuccess = _onSuccess, onFail = _onFail, })
stripe.listCharges(params)
-
Description:
- created: (string or table)(optional) A 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 table with key/value pairs as described on Stripe’s API documentation.
- customer: (string)(optional) Only return charges for the customer specified by this customer ID.
- ending_before: (string)(optional) A 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.
- limit: (number)(optional) A limit on the number of objects to be returned. Limit can range between 1 and 100 items. Defaults to 10.
- source: (table)(optional) A filter on the list based on the source of the charge. The table should contain one entry with the key “object” and a value of “all”, “alipay_account”, “bitcoin_receiver”, or “card.” Defaults to {object = “all”}
- starting_after: (string)(optional) A cursor for use in pagination. starting_after is an object ID that defines your place in the list. For instance, 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.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Retrieves a list of charges you’ve previously created. The charges are returned in sorted order, with the most recent charges appearing first.
Arguments:
stripe.listCharges() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s list all charges documentation for more details.
Returns:
A table containing at least one Stripe charge object to your onSuccess listener, in a numerically-indexed subtable called “data.” (see sample code below.) In the event of an error, a Corona networkRequest table is returned to your onFail listener.
NOTE: The table returned to your onSuccess function will contain a boolean “has_more” property. If has_more == true then there will also be a “getMore” property that is a function you can call to get the next “page” of results (using the same onSuccess and onFail functions), until there are no more.
Sample Code:
local function _onSuccess(charges, event) -- print charge IDs for all charges in the returned list for i = 1, #charges.data do local charge = charges.data[i] print(charge.id) end -- retrieve more results if they exist: if charges.has_more == true then charges.getMore() end end stripe.listCharges({ limit = 5, onSuccess = _onSuccess, onFail = _onFail, })
stripe.newCustomer(params)
-
Description:
- account_balance: (integer)(optional) An 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.
- description: (string)(optional) An arbitrary string that you can attach to a customer object. It is displayed alongside the customer in the dashboard.
- email: (string)(optional) Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking.
- metadata: (table)(optional) A 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.
- shipping: (table)(optional) A table containing contact information about the customer. See Stripe’s API documentation for a complete list of available “shipping” fields.
- source: (table)(optional) The source can either be a Stripe token ID, or a table containing a user’s credit card details. See Stripe’s API documentation for a complete list of available “source” fields.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Creates a new customer object on your Stripe account.
Arguments:
stripe.newCustomer() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s create a customer documentation for more details.
Returns:
A Stripe customer object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.newCustomer({ description = "d'oh!", shipping = { name = "Homer Simpson", address = { line1 = "742 Evergreen Terrace", city = "Springfield", country = "USA" }, }, onSuccess = _onSuccess, onFail = _onFail, })
stripe.getCustomer(params)
-
Description:
- customer: (string)(required) The identifier of the customer to be retrieved.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Retrieves the details of an existing customer.
Arguments:
stripe.getCustomer() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s retrieve a customer documentation for more details.
Returns:
A Stripe customer object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.getCustomer({ customer = "cus_7xQAtp4v9hte0V", onSuccess = _onSuccess, onFail = _onFail, })
stripe.updateCustomer(params)
-
Description:
- customer: (string)(required) The identifier of the customer to be updated.
- account_balance: (integer)(optional) An 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.
- description: (string)(optional) An arbitrary string that you can attach to a customer object. It is displayed alongside the customer in the dashboard.
- email: (string)(optional) Customer’s email address. It’s displayed alongside the customer in your dashboard and can be useful for searching and tracking.
- metadata: (table)(optional) A 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.
- shipping: (table)(optional) A table containing contact information about the customer. See Stripe’s API documentation for a complete list of available “shipping” fields.
- source: (table)(optional) The source can either be a Stripe token ID, or a table containing a user’s credit card details. See Stripe’s API documentation for a complete list of available “source” fields.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Updates the specified customer by setting the values of the parameters passed. Any parameters not provided will be left unchanged.
Arguments:
stripe.updateCustomer() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s update a customer documentation for more details.
Returns:
A Stripe customer object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.updateCustomer({ customer = "cus_7xQAtp4v9hte0V", metadata = { favorite_beer = "Duff", }, onSuccess = _onSuccess, onFail = _onFail, })
stripe.deleteCustomer(params)
-
Description:
- customer: (string)(required) The identifier of the customer to be deleted.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Permanently deletes a customer. It cannot be undone.
Arguments:
stripe.deleteCustomer() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s delete a customer documentation for more details.
Returns:
A table with two parameters (“deleted”, which will always be true, and “id” which is the identifier of the newly-deleted customer) to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.deleteCustomer({ customer = "cus_7xQAtp4v9hte0V", onSuccess = _onSuccess, onFail = _onFail, })
stripe.listCustomers(params)
-
Description:
- created: (string or table)(optional) A 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 table with key/value pairs as described on Stripe’s API documentation.
- ending_before: (string)(optional) A 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.
- limit: (number)(optional) A limit on the number of objects to be returned. Limit can range between 1 and 100 items. Defaults to 10.
- starting_after: (string)(optional) A cursor for use in pagination. starting_after is an object ID that defines your place in the list. For instance, 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.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Retrieves a list of your customers. The customers are returned sorted by creation date, with the most recent customers appearing first.
Arguments:
stripe.listCustomers() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s list all customers documentation for more details.
Returns:
A table containing at least one Stripe customer object to your onSuccess listener, in a numerically-indexed subtable called “data.” (see sample code below.) In the event of an error, a Corona networkRequest table is returned to your onFail listener.
NOTE: The table returned to your onSuccess function will contain a boolean “has_more” property. If has_more == true then there will also be a “getMore” property that is a function you can call to get the next “page” of results (using the same onSuccess and onFail functions), until there are no more.
Sample Code:
local function _onSuccess(customers, event) -- print customer IDs for all customers in the returned list for i = 1, #customers.data do local customer = customers.data[i] print(customer.id) end -- retrieve more results if they exist: if customers.has_more == true then customers.getMore() end end stripe.listCharges({ limit = 5, onSuccess = _onSuccess, onFail = _onFail, })
stripe.newToken(params)
-
Description:
- card: (table)(either card or bank_account are required) The card this token will represent.
- exp_month: (string)(required) Two digit number representing the card’s expiration month.
- exp_year: (string)(required) Two or four digit number representing the card’s expiration year.
- number: (string)(required) The card number, as a string without any separators.
- cvc: (string)(required) Card security code.
- address_city (optional)
- address_country (optional)
- address_line1 (optional)
- address_line2 (optional)
- name: Cardholder’s full name (optional)
- address_state (optional)
- address_zip (optional)
- bank_account: (table)(either card or bank_account are required) The bank account this token will represent.
- account_number: (string)(required) The account number for the bank account in string form. Must be a checking account.
- country: (string)(required) The country the bank account is in..
- currency: (string)(required) The currency the bank account is in. This must be a country/currency pairing that Stripe supports.
- routing_number: (string)(required for US bank accounts) The routing number, sort code, or other country-appropriate institution number for the bank account. For US bank accounts, this is required and should be the ACH routing number, not the wire routing number. If you are providing an IBAN for account_number, this field is not required.
- account_holder_name: (string)(optional) The name of the person or business that owns the bank account.
- account_holder_type: (string)(optional) The type of entity that holds the account. This can be either “individual” or “company”.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Creates a single use token that wraps the details of a credit card or bank account.
Arguments:
stripe.newToken() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s create a token documentation for more details. Note that either a “card” or “bank_account” table is required, but you can only submit one or the other.
Returns:
A Stripe token object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
-- create a credit card token: stripe.newToken({ card = { exp_month = "01", exp_year = "20", number = "4242424242424242", cvc = "123", name = "Moe Szyslak", }, onSuccess = _onSuccess, onFail = _onFail, }) -- create a bank account token: stripe.newToken({ bank_account = { country = "US", currency = "usd", name = "Moe Szyslak", account_holder_type = "individual", routing_number = "110000000", account_number = "000123456789", }, onSuccess = _onSuccess, onFail = _onFail, })
stripe.getToken(params)
-
Description:
- token: (required) a string referencing the ID of an existing Stripe token.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
Retrieves an existing token from Stripe’s servers.
Arguments:
stripe.getToken() accepts a single params table as an argument, with the below key/value pairs. See Stripe’s retrieve a token documentation for more details.
Returns:
A Stripe token object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
stripe.getToken({ token = "tok_17gEFnELWHyjUdjWh8PLy9hr", onSuccess = _onSuccess, onFail = _onFail, })
stripe.donate(params)
-
Description:
- amount: (number)(required) a positive integer representing the amount to be charged, in the lowest currency unit.
- currency: (string)(optional) a 3-letter ISO code for currency. Defaults to “usd”.
- onSuccess: (optional, but strongly suggested) an onSuccess function triggered after a successful connection to Stripe.
- onFail: (optional, but strongly suggested) an onFail function triggered after an unsuccessful connection to Stripe, or if Stripe returns an error.
- onCancel: (optional, but strongly suggested) a function triggered when a user manually closes the Checkout form without completing the checkout process.
Displays a Stripe Checkout form that results in a charge being deposited into the Stripe account of Jason Schroeder (the guy who wrote the Stripe plugin).
Okay, so this isn’t something that you’d really want to put in your own app, but if you really love the plugin and wanted to give me a few bucks for the effort, this is a way to do that. It’s also built into the sample app.
Arguments:
stripe.donate() accepts a single params table as an argument, with the below key/value pairs.
Returns:
A Stripe charge object to your onSuccess listener, or a Corona networkRequest table to your onFail listener.
Sample Code:
-- this would make a $10.00 donation: stripe.donate({ amount = 1000, currency = "usd", onSuccess = _onSuccess, onFail = _onFail, onCancel = _onCancel, })
Gotchas
Charge Amounts Must Be Integers
-
It is important to note that Stripe only handles charge amounts as integers – so all your charge amounts must represent the charge value in the lowest currency unit (for US dollars, this means cents). If you wanted to charge a customer fifty dollars, you would need to submit that amount as “5000” – were you to submit “50” or even “50.00”, the customer would only be charged fifty cents!
Test Card Numbers
-
When you are using the plugin with test API keys, Stripe’s servers will refuse any attempt to charge an actual credit card. However, Stripe provides a list of “dummy” card numbers for all supported card types so you can see first-hand how your app is handling charges while still in test mode. Additionally, Stripe provides other numbers that will trigger specific non-successful server responses, so you can test your app’s error handling. For example, entering card # “4000 0000 0000 0127” in test mode will cause a decline on account of an incorrect CVC security code, and card # “4000 0000 0000 0069” will cause a decline on account of an expired card. For a complete list of these “dummy” card numbers, please go to stripe.com/docs/testing.
Demo Project
I’ve created a free demonstration project that you can load in the simulator or build for device to see the Stripe plugin in action. The project is fully self-contained, so all you need to do is download it and open it in the simulator. However, you will need to open a Stripe account and add your API keys to the stripe.init() function call on line 5 of the project’s main.lua for it to work properly.
Here is a video of the app running in the Corona Simulator:
Excellent work and documentation! A greatly appreciate addition – thank you!
Thanks, Terry! I hope you’ll get some use from the plugin. Should be available any day now! 🙂
I thought you are not supposed to put your secret key in the client side of an app.
Thanks for commenting, Christian! In an ideal world, that’s true – you should be making calls from a secure server, and the secret key should not be in your app’s code.
I designed the plugin to operate without the need for a separate server to make the actual API requests to Stripe. It’s worth noting that there is another Lua-based Stripe library that Stripe links to on its official list of API Libraries (https://stripe.com/docs/libraries) that operates in much the same way, at least in regards to your secret key.
I would say that your Lua code gets converted into bytecode when you build for device with Corona, so there’s at least some measure of obfuscation going on. But if you really wanted to keep the key out of your code, you could come up with your own way of securely obtaining it via network request. This would prevent the key from actually appearing in your code (and could also give you the ability to generate a new set of API keys and push them to your app without having to submit an app update).
Alternatively, if you do have a server that you want to make the actual charges from, you can still use the plugin to generate tokens without an actual secret key. Since generating tokens can be done with only the publishable key, you could call stripe.init() with your actual publishable key and a “dummy” secret key. This would render all but stripe.newToken() and stripe.checkout() inoperable (and stripe.checkout would only work if you set chargeNow=false), since those functions require a working secret key. But doing so would allow you to obtain a token ID that you could then pass to your own server, to have the final charge API call make from a server (where the secret key is not user-facing).
Hope this helps, and thanks for stopping by the site!
Thanks Jason, I did think about getting the secret key from my secure server upon launch of my app, not ideal but not terrible. So I can create new customers, add cards etc. without the secret key, which actually maybe all I need as I have the server side process the payments as they are automated upon completion of a job.
Stripe is awesome, here is my web guide http://fearby.com/article/adding-secure-credit-card-payments-to-your-website/
Any idea when stripe.checkout() will be available for Android?
Hi Kevin,
No time soon unfortunately as stripe.checkout() requires a webview to run, and the Android version of Stripe’s “stripe.js” library that the webview loads requires the checkout page to open in a new window – something that doesn’t play nice with embedded app webviews. Check this CoronaLabs forum thread for more details on this topic: https://forums.coronalabs.com/topic/64547-stripe-plugin-javascript-modal-issue/
Got it.
I’m seeing an error both in the demo project and my app:
WARNING: plugin.stripe.checkout is not configured in build.settings
The demo seems to run fine and I have not made any changes to build.settings.
Hi Kevin,
It looks like you attempted to require a plugin specifically for stripe.checkout, which would cause that warning.
At any point in your code do you include require(“plugin.stripe.checkout”)? If so, that’s your problem. There is no “plugin.stripe.checkout” – just “plugin.stripe” – remove any attempt to require anything besides “plugin.stripe” and you should be good to go.
No, I only require plugin.stripe. Your demo project throws the same error without any changes from me. But as I said, it appears to be working…
Thanks Kevin. At least it’s working, but I’ll do some digging and see if I can eliminate that error message. CoronaLabs changed the way they distribute plugins in the last week or so, which could be part of the issue? Stay tuned.
@Kevin: I’m not able to replicate the issue, at least in the Corona simulator. Are you seeing this in the simulator or only on device? What OS are you running it on (Windows Simulator / OS X Simulator / iOS / Android)? Also, please download the latest daily build from Corona Labs first and confirm you are still seeing that error after doing so. Thanks!
Hey Jason,
First of all, killer work on the module. I can always count on you to make something that I need, kudos to you sir. Second, are there any plans on integrating stripe-connect?
Cheers,
Hi Jason,
really great job 😉
I really appreciate your work, thank you a lot .
Actually I’m facing a problem.
In the last month, Stripe is deprecating the TSL 1.0 and 1.1 and they are accepting TSL 1.2 only for security reasons
The problem it’s that Android OS before 5.0, not enable by default TLS 1.2 (although it’s already supported)
Can we force in any way the use of the TLS 1.2 with your plugin (I have seen there are some ways to do that in java)
Thank you in advance for your help
Hi Giorgio,
Unfortunately this isn’t something I’d be able to do directly in the plugin, at least not that I am aware of. The plugin is coded purely in Lua, and makes use of Corona’s built-in network.request() API for all network calls. To support this, you’d need to make sure that Corona updates their APIs to force TLS 1.2 compliance in earlier versions of Android.
You may want to open up a feature request at http://feedback.coronalabs.com. Hope that helps!
Hi Jason,
thank you for your quick answer
I did the feature request to Corona, I hope they will upgrade their API.
Thank you
Giorgio
Hi. I’m using your plugin. While testing I use card 4242424242424241and receive correct error message (“Invalid card number”), but all other test card for error checking (ex. 4000000000000119, 0069, 0127) give success result
Hi Massimiliano,
I was unable to reproduce the issue you reported. I successfully made a test transaction using 4242424242424242 – but in any case, the plugin worked as expected if you received a response from Stripe’s servers. The plugin simply sends and receives data from Stripe, so if the response is not as expected, you’d need to take it up with them, I’m afraid.