Mozilla

Implementing In-App Payments in Your Firefox OS App

At Mozilla, we have been working on bringing payments to the web. We think it is important that developers have an easy way to monetize their apps. It also gives us the chance to offer deeper platform integration, allowing things like carrier billing in addition to credit/debit cards.

We’ve talked about in-app payments before in navigator.mozPay() For Web Payments, but this is an overview from an app developer’s standpoint. This also includes a few updates, such as real payments being live in the Firefox Marketplace. Payments are different than simply being a paid app, which charges the user once on the initial purchase. In-app payments is a different workflow, and allows you to charge the customer for specific items within your app.

Architecture Overview

Payments are only enabled on Firefox OS devices for now. We are working on enabling them across other platforms, even desktop Firefox, but that is a ways off. For the rest of this article, we will assume the Firefox OS environment.

The MDN page for in-app payments has a good overview of the process, but here’s an even quicker overview. You need a server to generate the payments requests, because otherwise a hacker could easily change the prices to 0. The server creates JWT tokens, passes them to your app, and your app calls navigator.mozPay with the token. The user will be taken to a built-in payments workflow, and when finished, your server will be notified. The previous Hacks article on payments goes into the lower-level mechanics and reasons for payments more thoroughly.

It’s up to you to handle the rest of the workflow: updating the app when an item is successfully purchased, linking purchases to accounts, etc.

Getting a Simulation Key

In order to use payments, you’ll need use the app key and secret generated for you by the Marketplace. If you just want to simulate payments, you can easily grab a testing key and secret. The only thing you need to do is create an account if you haven’t done so already.

You will only be able to simulate payments with that key. When you are ready to use real money, you need to submit your app to the Marketplace, setup payments, and obtain a real key and secret. All of this is explained in more detail below.

Setting up the Server-Side Code

The first thing you need to do is set up the server-side code. A “mozpay” module exists in a few different languages which implements the payment workflow for you. If it does not exist in your programming language, you’ll need to use a JWT module and do some more legwork. Check the rather simple code from mozpay-js for an example of what you need to do.

I wrote a game for Firefox OS called Webfighter which uses node.js as the backend, so I used mozpay-js on the server-side. Webfighter is a shooter with a store where you can buy more weapons and ships, and it’s a good reference for developers to see actual code for working with payments. Examples below are taken from Webfighter. You can check out Webfighter’s source here.

First, require and configure the mozpay module:

var pay = require('mozpay');
var settings = require('settings');
 
pay.configure({
    mozPayKey: settings.payKey,
    mozPaySecret: settings.paySecret,
    mozPayAudience: 'marketplace.firefox.com',
    mozPayType: 'mozilla/payments/pay/v1',
    mozPayRoutePrefix: '/mozpay'
});

The settings module is just a file with JSON that specifies configuration of the app. It’s nice to separate the configuration so that you can easily swap it out in different environments, like development and production.

Use the key and secret that you got from the Marketplace. You should only change the audience and type options if you are using a different payment server than Mozilla’s. The routePrefix is optional and specifies the URL prefix for postbacks from the payment server.

Next you need to define a route that creates the data used for the payment transaction. The client is the one making the actual payments request (so that you don’t have to handle credit card details, and it’s possible to even be charged through carrier billing). You just need to create an object that represents a purchase. This example uses express.js as the http server.

var purchaseQueue = {};
 
app.post('/sign-jwt', function(req, res) {
    var token = 'o' + Date.now();
    var item = getItem(req.body.name);
 
    var jwt = pay.request({
        id: item.name,
        name: item.name,
        description: item.description,
        icons: { '64': settings.url + item.icon },
        pricePoint: item.price,
        productData: token,
        postbackURL: settings.url + 'mozpay/postback',
        chargebackURL: settings.url + 'mozpay/chargeback',
        simulate: { result: 'postback' }
    });
 
    // Keep track of which JWT objects we are waiting on
    purchaseQueue[token] = 'processing';
 
    res.send(JSON.stringify({
        jwt: jwt,
        token: token
    });
});

Notice the settings object again; it’s just a dict that has some configuration properties about our app. settings.url is the base URL where our app is hosted, so that all of the passed URLs are absolute.

We call getItem to get the details about an item (which we don’t define here). I found it easiest to define a JSON file containing info about all the available items. You can see the JSON for available items in Webfighter on GitHub.

There are several fields for a purchase request. id is just a unique identifer, and we simply use the product name. Other fields describe the product, such as icons which lists icons of various sizes. The pricePoint is a number that maps to a specific price for each available region, and you should look at the price point table to find the one you need. For example, a price point of 10 indicates a price of $0.99 in the US.

The simulate parameter tells the payments system to just simulate the request. If it’s passed, no real charges are made and you will be taken through a simulated workflow. This is useful for development. Just remember to remove this flag in production.

You can store anything you want to in productData, which you can later use when handling events. Here I generated an arbitrary token to track requests, and I store it in the global object purchaseQueue. We use this when we handle events.

Next, subscribe to the postback event from the mozpay module:

pay.on('postback', function(data) {
    // the payment was successful
    var req = data.request;
    purchaseQueue[req.productData] = 'success';
});

You can also subscribe to the chargeback event. Chargebacks happen when a customer disputes a charge and gets the money back. This could happen a month later, and is difficult to process. Webfighter keeps track of chargebacks, but the app does not check for them and revoke items. You would need to check periodically or on startup if the user still has access to all purchased items.

pay.on('chargeback', function(data) {
    var req = data.request;
    purchaseQueue[req.productData] = 'chargeback';
});

That’s it for the server-side.

Using mozPay On the Client Side

On the client-side, you need to post to /sign-swt and use mozPay to initiate the purchase. In the following code, we check if mozPay is available and if it’s not we just give the user the item. Remember, it’s just a test app! Once a purchase is initiated, we start polling the server until we get a successful purchase.

function buy(name) {
    // Purchase an item by requesting a JWT object from the
    // server, and posting it to the mozPay API
    $.post('/sign-jwt', { name: name }, function(res) {
        if(navigator.mozPay) {
            var req = navigator.mozPay([res.jwt]);
 
            req.onerror = function() {
                console.log('mozPay error: ' + this.error.name);
                clearPolling();
            };
 
            // Poll to see when the payment is complete
            startPolling();
        }
        else {
            alert('in-app payments unavailable, so giving it to you for free');
            onPurchase(name);
        }
    });
}

Here are the polling functions which wait until the server responds with a successful purchase. Note that we only check for a successful purchase. The user will be notified of any errors within the native payment screen, and when they close the screen an error event is fired on the mozPay request object, which we handle and stop the polling. See the above code with req.onerror.

function pollQueue(token, name) {
    // Poll the server every second to see the status of our
    // payment request
 
    $.get('/purchaseQueue?token=' + token, function(res) {
        if(res == 'success') {
            onPurchase(name); 
            clearPolling();
        }
    });
}
 
var pollTimer;
function startPolling() {
    pollTimer = setInterval(function() { pollQueue(res.token, name); }, 1000);
}
 
function clearPolling() {
    if(pollTimer) {
        clearInterval(pollTimer);
    }
    pollTimer = null;
}

We call onPurchase when an item is successfully purchased and should be enabled for the user. You should create that function and write your app-specific code.

Real payments: submitting app to the Firefox Marketplace

When you are ready to run real payments, remove the simulate field when the server creates the payment request, and submit your app to the Firefox Marketplace. It needs to be submitted so that you can hook up real payments.

Get paid: configuring bank account details and payment options

Once your app is submitted, edit your app and click on “Compatibility & Payments” on the left side and select “Paid / In-App”. Under “Payment Accounts”, and add your bank account. One thing that tripped me up was needing the SWIFT code for my bank. In the future, Marketplace will hopefully autofill it, but for now you can look it up on the theswiftcodes.com.

Under “Price & Countries” you can set the price for your app. You may just want “Free with in-app payments”, which is what Webfighter is. Additionally, you can selectively choose which region your app is available in. Apps with payments are only available in regions with them enabled.

Use a real key & secret

Now click the “In-App Payments” link in the left sidebar. You’ll see a screen where you can grab a new key & secret for real payments. Use these in the configure call on the server. Never share your secret.

At this time of writing, carrier billing is only available in specific countries. Check out the Payments Status page for where it’s available. When it is not available, the user will be presented with a credit card screen.

Go make some money with your app!

We want you to be successful in participating in the app ecosystem and economy. Let us know what your experience is like! We are happy to answer any questions over on the marketplace mailing list.

17 comments

Comments are now closed.

  1. Progi1984 wrote on November 26th, 2013 at 14:18:

    Good job for this article.

    When you have a packaged app, there is not server side. How can you implement in-app payments in packaged app ?

    1. James Long wrote on November 26th, 2013 at 14:31:

      You can still have a server with a packaged app, the app itself just doesn’t rely on it. As far as I know right now, you need a server to create and sign the payment data. When the payment processing is finished, the payment server sends an event back to you, so if you think about it that way you definitely need a server to handle that callback.

      The server would only handle payment handling, and that’s it. The rest of your app could work offline.

      1. Progi1984 wrote on November 26th, 2013 at 14:45:

        So is it no possible to implement in app payments without a server ?

        1. James Long wrote on November 26th, 2013 at 15:16:

          No, because how would the payments server send an event back to you when the payment is processed? Without a server, it has no URL to post to.

          You could use something like heroku which has a lightweight free plan for just managing the in-app payments.

          1. Progi1984 wrote on November 26th, 2013 at 15:52:

            If I understand, the dev connect its bank account to the Marketplace.

            An user go in the app, and want to buy an in app. He clicks on a button pay. That sends a request to /sign-jwt for obtain a signed JWT. The payment use this signed JWT and go in the payment workflow. After the success or failure of the payment, that sends a request to the postback url (success) or chargeback url (failure).

            Is it that ?

          2. James Long wrote on November 26th, 2013 at 16:45:

            Not exactly. Your workflow is right, but you need a server to handle the /sign-jwt request. Marketplace doesn’t do any hosting for you.

          3. Progi1984 wrote on November 27th, 2013 at 00:05:

            So except the request /sign-jwt, this is the process ?

            Have you got a backend PHP for managing this ?

          4. James Long wrote on November 27th, 2013 at 08:26:

            No PHP yet, read the “server-side” section above.

        2. Kumar McMillan wrote on November 26th, 2013 at 18:24:

          We plan to offer packaged apps (without a server) a way to do payments. It’s still under development so no ETA yet. You could cc yourself to this bug for updates https://bugzilla.mozilla.org/show_bug.cgi?id=910270

  2. Stuart Langridge wrote on November 26th, 2013 at 14:22:

    A brief question. It’s reasonably clear from https://developer.mozilla.org/en-US/docs/Mozilla/Marketplace/App_pricing?redirectlocale=en-US&redirectslug=Web%2FApps%2FPublishing%2FApp_pricing that if I’m using in-app payments in an app I wrote, that my financial relationship is with the payment provider, not with Mozilla. This is a reasonable thing for Moz to do, certainly; cut out the middle man, and so on, and I assume that it means that if there is a problem with me getting paid, that I take it up with the payment provider and not the Mozilla team. However, if that’s the case… why do Mozilla take a cut of the payment? Normally with these things, the operator of the app store takes a cut of the payment, but my financial relationship is with them; that is, if there’s a financial problem, I complain to the people who run the app store and the onus is on them to deal with it. With Moz stepping back (quite sensibly, perhaps) from that role… what’s my cut to Mozilla paying for?

    1. Andy McKay wrote on November 26th, 2013 at 14:49:

      At the very least Mozilla has to pay at the very least for the website development, infrastructure, marketing, maintenance and testing of the payment flow and a point of contact for payment support.

      Although the relationship is between the developer and the payment provider as the facilitator Mozilla has certain responsibilities. We’d try to keep everyone happy.

      1. Stuart Langridge wrote on November 26th, 2013 at 15:49:

        Fair play. Does this mean that anyone wishing to set up an alternative app marketplace would also need to take on those payment responsibilities in order to do so?

        1. Andy McKay wrote on November 26th, 2013 at 17:28:

          I guess that’s completely up to that person setting up that marketplace and how they want to implement payments.

          1. Stuart Langridge wrote on November 26th, 2013 at 18:22:

            Andy,
            I suppose I’m not understanding how navigator.mozPay works; if I set up an alternate marketplace, it seems that each app needs to know which marketplace it was sold through in order to know which marketplace’s payment stuff to talk to? So in a world where there are lots of marketplaces and not just one (something that’s been said repeatedly is the goal; this isn’t One True App Store lockin), how do I write apps? Do I need to make essentially a separate fork of my app for each marketplace I want to put it in?

        2. Kumar McMillan wrote on November 26th, 2013 at 18:32:

          You don’t have to fork your app for each marketplace. You do have to set up a payment account with each marketplace though. You can still use the same mozPay() API for each marketplace. In its current design you’d just pass an array of JWTs signed for each marketplace you support. In the future we may be able to improve the API for the case of multiple marketplaces but you definitely don’t have to fork your app.

          1. Stuart Langridge wrote on November 26th, 2013 at 18:41:

            Ah, cool; so in my server-side I’d just pass an array of key/secret/marketplace objects to pay.configure? That makes sense. And the app doesn’t care; it just passes over the JWT it got from the server?

          2. Kumar McMillan wrote on November 26th, 2013 at 18:43:

            yep, the app just bubbles up the signed JWT to mozPay(). You can’t sign a JWT on the client because there’s no secure way to handle a private key to make a signature.

Comments are closed for this article.