Contents
Overview
This is the provider specification for supporting the WebPayment API. A provider is responsible for the web pages that enable the buy flow behind navigator.mozPay()
when initiated on a device. At a high level, this is what a payment provider does:
- Serve a payment confirmation screen at a custom URL in this format:
https://<ANY_URI>?req=<JWT>
- Verify the incoming JWT signature
- Present product and price details (extracted from the JWT) for confirmation
- Process a payment from the customer
- Dispurse funds to the merchant
- When payment processing is finished, call
mozPaymentProvider.paymentSuccess()
ormozPaymentProvider.paymentFailed()
- Send server notifications to the merchant about the payment
The purpose of this document is to show how someone could implement a provider to hook into navigator.mozPay()
. As you will see, there are many relevant pieces to the payment provider that are important but that are out of scope for this document (summarized below).
There is also a Direct Billing API proposal that might replace this.
API
The navigator.mozPay()
implementation injects a global mozPaymentProvider
object within the payment provider's web page context.
interface mozPaymentProvider { /** * Close the payment window after success. The result will be returned to DOMRequest.result in navigator.mozPay(). */ void paymentSuccess(in DOMString result); /** * Close the payment window after failure. The result will be returned to DOMRequest.result in navigator.mozPay(). */ void paymentFailed(in DOMString error); /** * Send an MO (mobile originated) SMS without storing it on the device's SMS database or requesting delivery status. * The SMS will not show any notifications and will not appear in any SMS application consuming the WebSMS API. */ DOMRequest sendSilentSms(in DOMString number, in DOMString message); /** * Intercept any incoming MT (mobile terminated) SMS sent from the given number. */ void observeSilentSms(in DOMString number, in jsval callback); /** * Remove a previously observed number and its corresponding handler. */ void removeSilentSmsObserver(in DOMString number, in jsval callback); /** * Array of integrated circuit card IDs that are currently active on the mobile device. */ readonly attribute array iccIds; /** * Mobile Country Code (MCC) of the network operator */ readonly attribute unsigned short mcc; /** * Mobile Network Code (MNC) of the network operator */ readonly attribute unsigned short mnc; }
Multi-SIM Support
Invocation
- When an app triggers an in-app payment or when a marketplace triggers an app purchase, it invokes
navigator.mozPay()
in JavaScript with a JWT (JSON Web Token). - A window opens up on the customer’s device to a URL of the payment provider. This URL is determined by the typ field of the JWT but must also be in a special whitelist on the device. In the case of Firefox OS, for example, all new payment providers must work with Mozilla to have their URLs added to the whitelist that is shipped with devices.
- The user agent makes a GET request to the payment provider to load the payment screen. The URL looks like this:
https://paymentprovider.com/mozpay?req=<JWT>
- See the WebPayment API for details on the acceptable JWT parameters.
JWT Verification
- Before proceeding with any payment processing, the payment provider must verify the signature of the JWT (passed in as query string parameter
req
) so that it knows the authorized app truly requested the payment. - Since the JWT is base 64 encoded, the payment provider can first decode it and read the iss (issuer) from the JSON object.
- The JWT signature can be verified by using the shared secret that was granted to the issuer. See the Out of Scope section for how a merchant and payment provider would exchange a secret key.
User localization
The payment provider might need to locate the customer in order to allow or not payments depending on its region. In order to facilitate this, the mozPaymentProvider
API exposes the device's SIM MCC and MNC.
User identification
The payment provider will need to identify the customer in order to initiate a payment.
Mobile billing
In order to charge a user for a purchased digital good via carrier billing, the payment provider needs to identify the user as an authenticated carrier user. The way the user is identified depends on the capabilities of the carrier's network and on the device connection status. Some carriers provide a network based authentication mechanism where the users can be identified and authenticated by IP. This mechanism requires the user's device to have an active data connection (i.e. 3G) and it obviously won't work if the user's device is connected via WiFi. The network based authentication mechanism provides a seamless UX where the user can be "silently" authenticated. However, the requirements for this authentication mechanism are unfortunately not always met, so we also need to provide fallback mechanisms as an alternative to the network based one. One of these fallbacks is the SMS flow.
Silent SMS
The mozPaymentProvider
API exposes three methods for allowing the payment provider to do an SMS based authentication flow.
-
sendSilentSms(number, message)
, which allows the payment provider to send an MO (mobile originated) SMS without storing it on the device's SMS database or requesting delivery status, which means that the SMS will not show any notifications and will not appear in any SMS application consuming the WebSMS API. This function returns a DOMRequest object so the caller can check that the SMS is successfully sent. The number parameter is expected to be a short code.
-
observeSilentSms(number, callback)
, which allows to the payment provider to intercept any incoming MT (mobile terminated) SMS sent from the given number. The content of the intercepted SMS will be given to the payment provider through the callback provided as the second parameter in the form of a nsIDOMMozSmsMessage . Same as before, this means that the SMS will be shown in SMS application or notification. The SMS will be silent. The number parameter is expected to be a short code.
-
removeSilentSmsObserver(number, callback)
, which allows the payment provider to remove a previously observed number and its corresponding handler. This method will automatically be called with the completion of the payment flow (via 'paymentSuccess' or 'paymentFailed' calls or if the user manually closes the payment flow), so the payment provider doesn't need to do any manual clean up of the set up observers. This method is only exposed just in case the payment provider wants to remove a silent SMS observer before the completion of the whole payment flow.
A example flow for an SMS MO + SMS MT scenario with a fake 123 charge free short code could be something like:
- As the payment provider will be "talking" with the short code application for 123, the first step should be start observing the messages coming from that number. This is done via
mozPaymentProvider.observeSilentSms('123', onmessage);
, whereonmessage
is the callback that will handle the reception of an SMS coming from 123.
- Once it is ready to handle messages from 123, the payment provider requests to send an SMS via
var req = mozPaymentProvider.sendSilentSms('123', uuid);
. Whereuuid
is a variable containing the body of the SMS. It is recommendable to send a generated unique ID (uuid) as the message body, that will need to be sent back by the short code application, so the payment provider can match each send with its corresponding reply. The payment provider will need to keep track of these uuids and remove them as soon as a matching reply is received or after a timeout or send failure. Thereq
variable returned bysendSilentSms
is an instance of DOMRequest and allows the payment provider to check if the SMS is successfully sent or not.
- The message sent in the previous step is received by the short code application (on the carrier's side), which identifies the user as the sender of the SMS. The short code application sends back a message containing the uuid to the number of the sender of the previous message.
- The message sent by the short code application is intercepted by the payment provider and handled within the callback given to
mozPaymentProvider.observeSilentSms
in the first step. If the uuid is correct, the payment provider knows that the user is properly authenticated by the carrier side and so it can continue with the payment process.
- At this point, the payment provider should do its clean up for the uuid identifying the authentication flow. It can also call
mozPaymentProvider.removeSilentSmsObserver
, but as mentioned above, it is not mandatory.
An SMS MO only flow is quite simpler and only requires a call to mozPaymentProvider.sendSilentSms
.
Payment Confirmation
The JWT contains name, description, prices in various countries, and a suggestion for the what the customer’s default price would be. The payment provider must present this information in a clear and concise way so that the customer knows exactly what she is about to buy.
Payment Processing
When the customer clicks a button to complete payment, the provider can charge the customer for the amount of money in the selected currency. The payment provider would then dispatch the money to the merchant.
Completion
In order to allow the payment provider to control the behavior of the payment window, the mozPaymentProvider
API exposes paymentSuccess
and paymentFailed
. These functions should be called by the payment provider to finish the payment flow. Both functions would close the payment flow window and trigger the onsuccess or onerror events over the DOMRequest returned by the navigator.mozPay
call. The aResult
and aErrorMsg
strings passed by the payment provider would be available for the application as DOMRequest.result and DOMRequest.error values respectively.
- The success callback in the app is to say “the payment is done processing.” It does not guarantee a positive or negative outcome.
- The error callback is to indicate that the processing was cancelled or aborted somehow. The specific error code details are to be decided.
Cancellation
If the customer cancels the payment by closing the window or clicking a cancel button, the payment provider must call mozPaymentProvider.paymentFailed()
as described above.
Notifications
- When the payment processing is finished, the payment provider must send a POST to either a postback URL or chargeback URL of the app. These URLs are defined in the JWT passed into
navigator.mozPay()
for each request. - The payment provider signs a JWT with the same shared secret as with invocation and POSTs this to either the postback or chargeback URL. The POST must be a standard
application/x-www-form-urlencoded
request with the JWT passed as form parameternotice=JWT
. - The JWT must include the original request as well as an additional response object that specifies the payment provider’s transaction ID.
- When a payment is successful a notification is sent to the postback URL.
- When a payment is unsuccessful due to insufficient funds or some kind of processing failure a notification is sent the chargeback URL.
- If a payment is refunded some time in the future a notification is sent to the chargeback URL.
- The app must respond to the POST with a 200 OK status and must return a plain text response of the transaction ID.
- If the app server does not respond with a 200, the notification should be retried a few times and stored in a queue if the request never goes through.
See the WebPayment API for detailed examples of postback / chargeback notification JWTs.
Privacy
Since navigator.mozPay()
can be called in many contexts the payment provider may receive an initial GET request without the user knowingly attempting a payment. The privacy policy for collecting this data and all other data related to performing payments must be clearly stated on the provider hosted pages. Mozilla will review the data collection policy of all payment providers before adding them to the whitelist.
Out of Scope
As you can see, the navigator.mozPay()
API leaves a lot of implementation and user experience design up to the provider. Here are some out of scope items that are important things to consider when implementing a payment provider.
Merchant Setup
In order to begin making payments, a merchant and provider must exchange a secret key to sign JWTs with. The merchant will want to register their bank account details (or something) with the provider in order to get paid. The Payment Provider should be prepared to respond to compromised secrets by revoking them immediately.
PIN
It's a good idea to prompt the user for a PIN code (personal identification number) or something similar at the time of payment to prevent someone from picking up the device and immediately making payments. A customer would need to set up a PIN in advance.
Reference Implementation
Mozilla is building a web payment provider available at https://github.com/mozilla/webpay . You can install it from source at that link.