All Collections
Develop
Interacting with Passes from an app
Adding passes to Apple and Google Wallet directly from within my app?
Adding passes to Apple and Google Wallet directly from within my app?

Learn how to modify the Pass URLs to control the desired user experience.

Danny Allen avatar
Written by Danny Allen
Updated over a week ago

This article is for you if you:

  • Want to understand more about the PassKit Pass URL's, their purpose, and how they decide on the end-user experience.

  • Have an iOS and/or Android app, and want to allow your users to install or access their passes directly from within your app.

  • Simply want to download the Apple Pass Bundle (.pkpass file) to analyse its contents for debugging or educational purpose.

Prerequisites:

  • You have created a pass record using the PassKit Web Portal or any of the PassKit API's, and have obtained the PassKit ID.

  • The pass record is valid and not expired (note that passes in test projects automatically expire within 48 hours).

TIP: get the PassKit ID from within the Members or Coupons view inside the Web Portal:

The PassKit Pass URL

The PassKit Pass URLs - also referred to as the Pass Landing Pages, or Pass URLs - are public pages, and can be access by anyone with access to the URL. Their main purpose is to be distributed to end users, and allow the end user to download and install their pass.

A Pass URL is unique for a pass record, and contains the 22 character PassKit ID. The PassKit ID is an alphanumeric representation of a 128bit UUID which offers sufficient entropy to protect against random guessing.

A user need to know their pass url to be able to download their pass, and they are unable to guess another user’s pass by playing with the URL. Therefor Pass URLs do not require authentication.

The default format of the Pass URL:

Data Region: Europe

https://pub1.pskt.io/{{PassKit ID}}

Data Region: USA

https://pub2.pskt.io/{{PassKit ID}}

The service running behind the Pass URL is a proprietary, very unique and clever piece of software, that performs device detection and sends the user down the most appropriate end-user experience based on their device and user agent:

  • Apple Wallet: prompts the pass for adding to Apple Wallet in case of iOS users, or users that are running Safari or Chrome on OSX.

  • Google Wallet: if the user is an Android user AND IF the PassKit project the pass belongs to is configured with Google Pay as the default Android wallet (this is the default option) - will present the Google Pay end-user experience.

  • Third Party Android Wallet Apps: if the user is an Android user AND IF the PassKit project the pass belongs to is configured with either PassWallet or WalletPasses as the default Android wallet (recommend for countries where Google Pay is not yet supported) - will present the Third Party Android Wallet end-user experience.

  • Desktop: if the user visits from desktop from a browser that doesn't support the Apple Wallet journey, will present the user with instructions and a QR code to get the user to open the Pass URL on their mobile device.

This behavior is great when links are distributed via email, SMS or another channel where you don't know the Operating System and / or device of the user. But in a scenario where you want your user to install a pass from within your iOS or Android app, and already know what device they are on, we offer further configuration of the Pass URLs for a more controlled experience to directly link to the correct pass asset.

Installing a pass into Apple Wallet from within an iOS app

Append the Pass URL with .pkpass. i.e. https://pub1.pskt.io/{{PassKit ID}}.pkpass or https://pub2.pskt.io/{{PassKit ID}}.pkpass, then call the endpoint with a client that is capable of processing a .pkpass file. The recommend way to do this for iOS is with NSURL.

Most of the programmatic ways of calling the PassKit pass bundle URL endpoint in Java, Kotlin, Swift, cURL, etc. are covered, but if instead of getting back the binary data of the .pkpass bundle, you are getting back HTML, then you may be calling the endpoint with an unsupported user agent (for example when trying to get a pass through a UIWebView component in an iOS app). In order to resolve for this, simply add PassKit into the user agent string when making the request.

Once you have successfully retrieved the pass bundle, load the bundle into the PKAddPassesViewController to add the pass into Apple Wallet. More detailed instructions on what steps to take can be found in the official Apple Documentation.

Sample cURL with the correct and expected response:

curl -I https://pub1.pskt.io/26M0JjuCpGHBqPYvnlE4RF.pkpass
HTTP/2 200
server: nginx/1.19.0
date: Tue, 02 Feb 2021 18:04:30 GMT
content-type: application/vnd.apple.pkpass
content-length: 322897
access-control-allow-methods: OPTIONS, GET
access-control-allow-origin: *
access-control-expose-headers: Cache-Control, Content-Disposition, Content-Language, Content-Length, Content-Transfer-Encoding, Expires, Content-Type, ETag, Last-Modified, X-PassKit-PID
cache-control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
content-disposition: attachment; filename="26M0JjuCpGHBqPYvnlE4RF.pkpass"
content-transfer-encoding: binary
etag: 900c55c45f5cfdd0df2387fb8dbb2633
last-modified: Tue, 02 Feb 2021 18:04:30 UTC
x-passkit-pid: 26M0JjuCpGHBqPYvnlE4RF
strict-transport-security: max-age=15724800; includeSubDomains

Installing a pass into Google Wallet from within an Android app

Append the Pass URL with .gpay. i.e. https://pub1.pskt.io/{{PassKit ID}}.gpay or https://pub2.pskt.io/{{PassKit ID}}.gpay, and simply redirect your user to the URL.

Google will then handle the rest (including authenticating the user with their Google Account if they are unauthenticated):

  • If the user has Google Pay already installed, they will be directed to the Google Pay app which will then load in the pass.

  • If the user does not have Google Pay installed, then they will complete the process via the browser, then be presented a link to install Google Pay and load in the pass.

  • If Google Pay is not supported in the country of the user, then they will only be able to view the pass through the Google Pay web-browser experience.

There is no .pkpass bundle or other file based process like with Apple Wallet.

Downloading and analysing the .pkpass bundle

Append the Pass URL with .wallet. i.e. https://pub1.pskt.io/{{PassKit ID}}.wallet or https://pub2.pskt.io/{{PassKit ID}}.wallet, and load this from a browser other than Safari (this is important):

Alternatively you can download the bundle file with cURL:

curl https://pub1.pskt.io/26M0JjuCpGHBqPYvnlE4RF.pkpass --output pass.pkpass

To inspect the bundle, rename it from .pkpass to .zip and you are able to see all the files it contains:

Bonus: deleting a pass from Apple Wallet using your iOS app

Apple provides functionality to programmatically remove passes from Apple Wallet, all from within your app, without your user explicitly having to go into Apple Wallet and tap 'Remove Pass' on the back of the pass.

Before you implement this, it's important to understand Apple's guidelines for interacting with passes, in particular the bit on Removing a Pass:

Removing a Pass

Use the removePass: method of the PKPassLibrary class to remove a pass.

Remember that passes belong to the user, not to your app. Passes should be removed only in response to a direct user action. Never remove a pass without the user’s consent, even if the pass has expired or is outdated.

In addition to the above, the other prerequisite for removing a pass programatically, is that you are the owner of the pass. This means that the pass needs to be signed with your Apple Certificate, and this certificate needs to belong to the same Apple Developer Team as your app certificate (the Team Identifiers need to match).

Add your own Apple Pass Certificates to your account to publish "Live" projects under your own Apple Certificate and unlock this functionality.

Note: this functionality is not available with "Test" projects as these are using a PassKit demo certificate.

Did this answer your question?