Marketplace feature removal
The functionality described on this page no longer works — Firefox Marketplace has discontinued support for Android, Desktop, Tablets, and payments (and other related functionality). For more information, read the Future of Marketplace FAQ.
fxPay
is a JavaScript library for web applications to process in-app payments and restore purchased products from receipts. It's a wrapper around the services offered by the Firefox Marketplace API and is an alternative to mozPay. Unlike mozPay, fxPay is a complete solution for working with in-app products.
Note: To accept in-app payments on as many platforms as possible, use fxPay instead of using mozPay directly.
fxpay support
The fxpay library aims to eventually work in all web runtimes but the following platforms are officially supported at the moment:
- Firefox OS
- Firefox for Android
- This includes web apps running as Android APKs
- Firefox for desktop
- This includes desktop apps
Packaged App Restrictions
If you want to accept payments with fxpay in a packaged app, there are a few restrictions:
- Your manifest must declare an origin for receipt validation.
- Your app must be privileged so that it can define an origin.
- Your app can only run on Firefox OS 1.1 or greater because of origin support.
None of this applies to hosted apps.
Usage Guide
This section provides a full usage guide for fxpay.
Installation
To use fxpay
, include a copy of the JavaScript library locally in your web application. Using the Bower package manager, this command would install the library into your app:
bower install fxpay
You could then link to the library in your app's HTML using a script tag:
<script src="bower_components/fxpay/lib/fxpay.js" type="text/javascript"></script>
Alternatively you can use Bower tools to load and/or compress your managed scripts.
Source Distribution
You can download the latest stable source via fxpay's Git repository.
Using UMD or RequireJS
The fxpay
JavaScript distribution is exposed using the Universal Module Definition (UMD) format and is also RequireJS compatible.
Set Up Your Products
Log into the Firefox Marketplace Developer Hub and upload your app following the submission process. On the Compatability & Payments page under Prices & Countries set in-app payments to Yes and save the change. Now open the In-App Payments page and click Configure In-App Products, which opens the In-App Products page where you can create and edit your in-app products. For more information on using this page, see In-App Products.
If you want to test out fxpay
before setting up your products, skip to the Working with Fake Products section.
Fetching Products
Call fxpay.getProducts()
to retrieve all of the active products you set up in the Developer Hub:
fxpay.getProducts() .then(function(products) { products.forEach(function(product) { console.log('product ID:', product.productId); console.log('product name:', product.name); }); }) .catch(function(error) { console.error('Error getting products: ' + error); });
The getProducts()
promise
is resolved with an array of product info objects and rejected with an error object. You can call this method to show a list of products so the user can purchase them.
Working with Fake Products
To test in-app purchases without first configuring products on the Firefox Marketplace Developer Hub, you can work with fake products. Set this somewhere in your app's initialization:
fxpay.configure({fakeProducts: true});
This changes fxpay.getProducts()
to return pre-defined products that can only be purchased in simulation mode. The products will have fixed ID strings, names, and price points but this should help you set up your fulfillment code.
When you have submitted your finished app and fully configured your products, set fakeProducts
to false and the same call to
fxpay.getProducts()
will retrieve your app's real products.
Purchasing A Product
You can call fxpay.purchase()
to start the buy flow for an item. First, you'll probably want to make a screen where you offer some products for purchase using fxpay.getProducts()
. Here's how to create a buy button that calls fxpay.purchase()
when tapped:
fxpay.getProducts() .then(function(products) { products.forEach(function(product) { var button = document.createElement('button'); button.textContent = 'Buy ' + product.name; button.addEventListener('click', function () { fxpay.purchase(product.productId) .then(function(purchasedProduct) { console.log('product purchased! ', purchasedProduct.productId); // It is now safe to deliver the product. }) .catch(function(error) { console.error('error purchasing: ' + error); }); }); document.body.appendChild(button); }); });
The purchase()
promise
resolves with a product info object and is rejected with an error object. The promise resolves only after the user completes the buy flow and the Marketplace server has verified the receipt so at this time it is safe to deliver the item.
How does this work? The fxpay.purchase()
function automates the process of opening a payment window, completing the transaction, then waiting for and verifying an incoming JWT. If you want to know the specifics, see the mozPay in-app payments guide but that's not mandatory for using the fxpay
library.
Restoring Products From Receipt
fxpay
will discover any receipts already installed on the user's device. If a receipt is valid then the user has already purchased the product so you should make it available for use. You can check for receipts and validate them while fetching products like this:
fxpay.getProducts() .then(function(products) { products.forEach(function(product) { if (product.hasReceipt()) { product.validateReceipt() .then(function(restoredProduct) { console.log('restored product from receipt:', restoredProduct.productId); }) .catch(function(error) { console.error('Error validating receipt: ' + error); }); } else { // Show a buy button for the product. } }); });
Persisting Purchase Receipts
When fxpay.purchase()
resolves, a receipt is installed on the user's device and backed up in the Firefox Marketplace database. FxPay
does not offer a feature for restoring receipts on new devices yet but you could capture a receipt for later restoration like this:
fxpay.purchase(product.productId) .then(function(purchasedProduct) { console.log('purchase receipt:', purchasedProduct.receiptInfo.receipt); // Ask the user to log in then save the base 64 // encoded receipt string to your server with // their user ID. });
When fxpay supports receipt restoration, all historic purchase receipts will be made available.
Validating an app receipt
Although this is not directly involved with in-app purchases, it is worth knowing that fxpay provides a mechanism to check the receipt of a paid app when it is loaded on the user's device. This is done with the validateAppReceipt()
method, as seen below:
fxpay.validateAppReceipt() .then(function(productInfo) { console.log('receipt is valid; app was purchased'); console.log('product URL:', productInfo.productUrl); }) .catch(function(reason) { console.log('receipt is INVALID; reason:', reason.error || reason); });
If a valid app receipt is found, the promise resolves with a productInfo object that allows you to retrieve further info about the installed app. If not the promise rejects with a rejection reason (an object or a DOMString
).
To see the code above in context, look at our fxpay example on Github. If you want to run the example app, follow the installation instructions. Some further notes:
- The
allowTestReceipts
option is a useful configuration option for using test receipts to test that your code is validating receipts correctly (see Test Receipts for more information.) You should make sure to turn this off in production, otherwise people can use your app for free with test receipts.
fxpay reference
This section provides a reference to important objects contained in the fxpay code, and other available features.
Product Info Object
Many different promises resolve with a product info object. Error objects also have a productInfo
property which points to such an object. The product info object has the following properties:
- product.productId
- A unique string identifier for the product. This corresponds to the identifier you see in the Firefox Marketplace Developer Hub when managing your products.
- product.name
- The name of the product in the default locale.
- product.productUrl
- The URL of the product as declared in the receipt. This will most likely be a URL to the app, such as
https://your-hosted-app
orapp://your-packaged-app
. - product.smallImageUrl
- A 64 pixel square image URL for the product.
- product.pricePointId
- A reference to the price point chosen during product configuration.
- product.receiptInfo
- If the product has been purchased, this object gives you more information about the receipt. If the product has not been purchased the property will be falsey.
- product.receiptInfo.status
- A string status of the receipt, as returned by the validation service. Possible values: "ok", "pending", "refunded", "expired" or "invalid."
- product.receiptInfo.reason
- For invalid receipts only, this string indicates the reason it was invalid.
- product.receiptInfo.receipt
- The original web application receipt string. You can cache this in your application to manage restoration of user purchases yourself.
Errors
Promises are rejected with class-like objects that are subclasses of Error
. The following is a guide to the hierarchy of errors so you can catch them and react accordingly. Most errors will also have a productInfo
property which points to a relevant product info object.
Here's an example of ignoring cancelled payments and reacting to payment failures:
fxpay.getProducts() .then(function(products) { // ... }) .catch(function(error) { console.error('Error: ' + error); if (error instanceof fxpay.errors.PayWindowClosedByUser) { console.info('user cancelled the payment'); } else if (error instanceof fxpay.errors.PaymentFailed) { // Maybe show some info on how to purchase. } else { throw error; } });
General Errors
- fxpay.errors.FxPayError
- This is the root subclass for all errors thrown from FxPay. A check like
if error instanceof FxPayError
will always be true.
Subclasses of FxPayError:
- fxpay.errors.ConfigurationError
- A problem with how FxPay was configued.
- fxpay.errors.FailedWindowMessage
- A failure while communicating with another window as part of the payment.
- fxpay.errors.IncorrectUsage
- An interface in FxPay was used incorrectly.
- fxpay.errors.InvalidApp
- The app involved in the purchased is somehow invalid.
- fxpay.errors.InvalidJwt
- The JWT (JSON Web Token) used to begin payment is invalid.
- fxpay.errors.NotImplementedError
- The feature you are trying to use isn't fully implemented yet.
- fxpay.errors.PayWindowClosedByUser
- The payment window was closed by the user, perhaps by pressing a Cancel button. This will additionally have a
code
attribute ofDIALOG_CLOSED_BY_USER
. You will probably want to ignore this error. - fxpay.errors.UnknownMessageOrigin
- FxPay received a window message from an unknown origin.
Failed Payments
- fxpay.errors.PaymentFailed
- This is the root subclass for all errors relating to payment failures. You can check for this error if you want to show the user an informative message about how to complete or retry the payment.
Subclasses of PaymentFailed:
- fxpay.errors.AppReceiptMissing
- No receipt could be found to prove ownership of the application.
- fxpay.errors.InvalidReceipt
- The app receipt or in-app product receipt was invalid.
- fxpay.errors.PurchaseTimeout
- The API request or process to complete the purchased timed out and likely was not completed.
- fxpay.errors.TestReceiptNotAllowed
- A test receipt was presented but FxPay was not configured to allow test receipts.
Platform Errors
- fxpay.errors.PlatformError
- This is the root subclass for all errors that originate from the underlying payment platform instead of from FxPay.
Subclasses of PlatformError:
- fxpay.errors.AddReceiptError
- An error was returned while working with the
mozApps.addReceipt
API. - fxpay.errors.PayPlatformError
- A general error returned while working with a mozApps APIs.
- fxpay.errors.PayPlatformUnavailable
- The FxPay feature you're using requires a payments platform, such as mozApps, but none was found.
API Errors
- fxpay.errors.ApiError
- This is the root subclass for errors that can occurr while working with external APIs such as the Firefox Marketplace.
Subclasses of ApiError:
- fxpay.errors.ApiRequestAborted
- A request to the API was aborted.
- fxpay.errors.ApiRequestError
- A general error was returned while working with the API.
- fxpay.errors.ApiRequestTimeout
- A request to the API timed out.
- fxpay.errors.BadApiResponse
- An unexpected response was returned from the API.
- fxpay.errors.BadJsonResponse
- The JSON data from an API response could not be parsed.
Logging
By default, fxpay
logs everything using window.console. If you want to replace console
with your own logger, pass in an object as log
that implements the same window.console methods:
fxpay.configure({log: myConsole});
Configuration
You can call fxpay.configure(overrides)
to set some internal variables. If you call this repeatedly, the old keys will be preserved unless overidden.
fxpay.configure({apiTimeoutMs: 3000});
Possible overrides:
- apiUrlBase
- The base URL of the internal
fxpay
API. Default:https://marketplace.firefox.com
. - apiTimeoutMs
- A length of time in milleseconds until any API request will time out. Default: 10000.
- apiVersionPrefix
- A Path that gets appended to
apiUrlBase
to access the right API version. Default:/api/v1
. - fakeProducts
- If true,
fxpay.getProducts()
will return fake products that can be used for testing. See fake products for details. Default:false
. - log
- A log object compatible with window.console to use internally. Default:
window.console
. - receiptCheckSites
- Array of sites allowed to verify purchase receipts. These values are top level URLs to verifier services; they don't need to include URL paths. You would only need to adjust this if you want to work with something other than the production version of Firefox Marketplace. Default:
['https://receiptcheck.marketplace.firefox.com']
.
Migrating from old fxpay versions
The following release notes will help you update your code for major changes:
- Version 0.0.15
- Callback style was deprecated in favor of promises.
fxpay.init()
was deprecated.- Errors codes changed from strings to objects.
See also
- The development project for fxPay is hosted GitHub.
- See the fxpay working example for a full example of how to use it. The README on that page has instructions for how to install the example app on a Firefox OS device; the app can also be used to test
fxpay
and associated APIs. - If you find a bug with the fxpay library you can file a bug here on Github.