Passbook Programming Guide

Passbook Ecosystem Design

There are three major parts to the pass life cycle: creation, management, and redemption. Passbook handles the middle; it lets users view and manage their passes and provides lock screen integration. You are responsible for the two ends: creating passes and redeeming passes.

You Create and Distribute Passes

You are responsible for distributing passes to your users. Mail and Safari understand how to work with passes—on iOS they install passes directly, and on OS X they install passes via iCloud—so you can use them to add passes. Your app can also install passes using the Pass Kit framework.

Passes Are Presented and Managed by the Passbook App

You control the visual appearance by specifying a pass style, providing images, and setting colors and text formatting. Passes contain text, images, and a barcode. The Passbook app handles the details of layout and presenting a pass on the screen for you, and it provides the interface for the user to manage and delete passes.

Your App Can Interact with Passes Using Pass Kit

The Pass Kit framework provides an Objective-C interface for apps to interact with passes in the Passbook library. Companion apps should not duplicate the functionality of the Passbook app, rather they should enrich the user experience by doing things that Passbook can’t do such as letting the user ask for a different seat on a flight and then updating the pass. Passes need to be useful use even if the user doesn’t have your app installed.

Your app can only interact with passes whose pass type identifier matches the app’s entitlements—either passes you created or some subset of those passes.

Your Server Can Update Passes

Updating passes is a cooperative effort between your server and Passbook. When information on a pass changes, your server sends a push notification to the user’s device. The device communicates with your server to find out what has changed and to get the latest version of your passes.

Passes are updated by providing the latest version of the pass, not by providing a list of what changed. Anything in the pass can be updated except for the pass type ID and serial number. However, only certain kinds of changes actually make sense to the user. Updating a train ticket to reflect a delayed departure or a store card to show the current balance keeps the pass current and wouldn’t cause confusion. Replacing a coupon for a free order of breadsticks with a coupon for a free drink is likely to confuse the user—from the user’s perspective, one coupon disappeared and another coupon was unexpectedly added. In that case, you should create a new pass for the drink coupon.

You Are Responsible for Pass Redemption

Policies regarding when passes are valid or how many times they can be redeemed are your responsibility. Likewise, the effects of redeeming a pass such as updating a balance in your records are up to you. The following sections describe several use cases for passes and explain how you might implement them. These use cases illustrate interesting ideas and approaches; they’re not meant to be fully worked solutions.

Pass for a One-Time-Use Coupon

Suppose you want to give out a coupon for 10 percent off that can only be used once. You include a unique number on each coupon from 1 to 500, and you write the numbers 1 through 500 on a piece of paper next to the cash register. When the cashiers ring up a coupon, they consult the paper and cross off that coupon’s number.

This works on a very small scale, and illustrates the principle of a central trusted authority. You don’t control what your customers do with their passes or devices (or even with their paper coupons) so you can’t use that as a starting point for trusting information. Instead, you trust your database, and use the pass as a quick way to look up a particular record. The data in the pass itself is just a snapshot of some particular database state.

Doing it with passes is similar: the pass includes a unique ID in its barcode, and your server keeps track of which passes are still valid. At the point of redemption, you scan the barcode and consult your server to determine whether the pass is valid.

Don’t try to make a one-time-use pass by only giving the pass to a single device. Users with multiple iOS devices want your pass on all of their devices and iCloud syncs their passes across devices for them. If you email your pass to your users, they can forward the email and its pass. Your scanning and redemption system is responsible for implementing policies like “this pass is only valid once”.

Don’t try to expire or void a pass by pushing an update. Updates are not guaranteed to be delivered: the user may not have a network connection or may have disabled updates for the pass. Instead, update your database to indicate that the pass is invalid, and consult your database when the pass is redeemed. Additionally, your app should not remove expired passes without the user’s consent.

Pass for a Store Card with a Balance

Suppose you own a coffee shop and your customers typically pay with a card carries a balance, such as a gift card or store card. Similar to the one-time-use pass, you need a piece of information and it must come from a trustworthy source. In that case you needed to know whether the pass was still valid; in this case you want to know the pass’s current balance.

The implementation is similar. Each pass has a unique ID in the barcode which is scanned at the point of sale. Before completing the sale, you consult your server to record the transaction and update the balance. Once this is done, the cashier completes the sale.

You could take several approaches to verify that the person presenting the pass is actually the account holder. A generic card can include a thumbnail image, so you could put the account holder’s picture on the pass. For greater security, you could store the account holder’s picture in your database and display it on the cashier’s screen rather than trusting the pass. Other approaches are also possible, such as asking for a photo ID.

At some point after the sale, your server pushes an update to the pass with the new balance. This lets your users easily check their balance as it’s displayed right on the pass. This update can be handled by a different server that implements the web service API.

Pass for a Season Membership

Suppose you work for a museum that supports Passbook for its annual memberships. You want to let your members use the same pass for the entire year, with occasional updates to keep information about traveling exhibits current.

Ideally, the pass needs a unique ID in the barcode that you can scan at the museum entrance, to verify with your server that the membership is still valid. However, this is an situation where it’s possible to establish trust without consulting your server. (For example, if your scanners don’t have a network connection.) In addition to the unique ID in the barcode, you now include the year that the pass is valid, followed by a cryptographic signature of the ID and year. The signature lets you check that the contents of the barcode came from your server, and is therefore trustworthy.

This approach would not let you implement a one-time-use coupon without network access at the scanner; that’s essentially an unsolvable problem. It works here because the barcode contains an unchanging fact—a year that the membership is valid—and that is the only piece of information needed to determine whether the pass is still valid. Scanning the museum pass doesn’t change any state. In contrast, scanning a one-time-use coupon does change state: it voids the coupon. Without network access at the scanner, there is no way to get the latest state of the world before scanning or inform others of a state change after scanning.