Application Programming Interface (API)

PassSource has been helping people create Apple Wallet passes since they were announced by Apple. We've had lots of experience with different industries and users and have identified several features that are unique to PassSource that allow adding significant power and capabilities to our templates without having to write a single line of code. Our API was always designed to be easy to use and test and we've extended this philosophy to our advanced features that are available to our professional accounts.

Table of Contents


PassSource uses templates to create prototypical passes from which passes can be created. Changes to the template will propagate to passes when they are updated (if no update is sent or requested, they won't see the change). If a pass has overridden the template value and the original template value changes, this will not change the override (i.e. it will still be overridden with the pass value).

Advanced Features

PassSource templates have some advanced features unavailable anywhere else that allow powerful workflows without having to write any code. You can use these features with or without using the API and many of the features eliminate the need to use the API.

API Paths

Most of the attributes of a pass are exposed via our API Paths which are used to identify values and fields. These are used for the PassSource advanced features as well as in API calls.

You can find the API path for a field in the template editor. Click on the (i) button to the right of a field to get advanced options and see the API path.

The path for additional properties are simply the key.

In addition, we've made it easier to change the pass type and the transit type by exposing the following paths:

"Magic" Strings

We've implemented something we call "magic" strings which is a fancy way of saying, anytime we have a string in a pass, we automatically look for certain special strings and automatically replace the values when creating the pass.

You can use any API path as a magic string by surrounding the path in curly brackets. For example, if you wanted to include the points balance in some text on a backfield, you could include {structure_headerFields_points_value} in the text, and when the pass is created, it will be replaced with whatever value is in the structure_headerFields_points_value field. Or if you wanted to have the user's name included in the barcode message, you might set the barcode_message value to {memberId} {structure_secondaryFields_name_value}.

Note that to prevent users from using magic strings in registration fields, curly brackets are escaped. However, if you're using the API to set these values, they will not be escaped if you use your client hash to authenticate the edit.

In addition to paths, we also have some special strings that are available to use:

rootPathThis is replaced with the PassSource URL (currently This is useful if you are switching between the beta environment or just for simplicity.
clientHashBe very careful when including this as this will contain your client hash which can be used to update passes and templates. Typically, you would only use this for special additional PassSource features like the psInformationURL in the Pass Scanner app or on other internal pages or using triggers to call the API. Note that if you include this in a URL, if it is the end of a URL, add an ampersand (&) at the end if you include this in a back field with autodetection as the client hash may end with a comma (,) which will not be included but will cause problems when trying to decode the hash.
clientIdIf you want the user to go to branded white-label pages, you may want to provide your client ID. This is much safer to include than the client hash as there is nothing that can be exposed other than public branding information.
templateHashThe template hash for the pass. Typically used if you are creating a link to a new registration page for a share link or if you're executing triggers that call API functions that require the template hash.
hashedSerialNumberThe hashed serial number to this specific pass. This is often used to link to the registration page or custom service pages.
timestampSet to the current timestamp in ISO 8601 time format (GMT time). Can be used for example to set a membership start date in an onRegister trigger.
psPassURLA convenience path that maps to "{rootPath}/pass/create.php?hashedSerialNumber={hashedSerialNumber}".
psRegisterURLA convenience path that maps to "{rootPath}/pass/register.php?hashedSerialNumber={hashedSerialNumber}".
psEditorURLA convenience path that maps to "{rootPath}/pass/editor.php?clientHash={clientHash}&hashedSerialNumber={hashedSerialNumber}". Be very careful when including this as this will contain your client hash which can be used to update passes and templates. This is a convenience path for setting psInformationURL for the Pass Scanner app. If psEditCode is in the template, instead of the clientHash, it will include the templateId and the psEditCode. If this is used with :PassScannerConfig or in the psPortalHeader, it will not include the hashedSerialNumber.
psScanURLA convenience path that maps to "{rootPath}/pass/scan.php?clientHash={clientHash}". Be very careful when including this as this will contain your client hash which can be used to update passes and templates. This is a convenience path for setting up the Pass Scanner app with a custom URL. If psEditCode is in the template, instead of the clientHash, it will include the templateId and the psEditCode.
psScannerConfigURLA convenience path that expands to {psScanURL:PassScannerConfig} for configuring the Pass Scanner app. Be very careful when including this as this will contain your client hash which can be used to update passes and templates. If psEditCode is in the template, instead of the clientHash, it will include the templateId and the psEditCode.
PSColorGreenA convenience constant for our approved scan color. Currently resolves to rgb(77,186,11) but may be changed in the future.
PSColorYellowA convenience constant for our warning scan color. Currently resolves to rgb(187,187,58) but may be changed in the future.
PSColorRedA convenience constant for our error scan color. Currently resolves to rgb(187,49,58) but may be changed in the future.
Note that our special PassSource additional properties are also available as magic strings.

Magic strings also support some special transformations. For example, to get the URLEncoded value for the scan URL, you could use {psScanURL:URLEncoded}.

:URLEncodedPerforms a URL encoding on the string before replacing. Useful when specifying a value as a parameter in a URL.
:EscapedQuotesEscapes double quotes in the string by adding a backslash before the double-quote.
:PassScannerConfigGenerates a URL for configuring the Pass Scanner app (sets the customURL parameter to the value stored in the key). This works with our convenience URLs like psScanURL or psEditorURL and maps to "passscanner://?customURL={KEYED_VALUE:URLEncoded}" as well as including configuration to match the first beacon if specified.

You can link to the registration page by creating a backField with the attributed value set to: <a href="{psRegisterURL}">Register your pass!</a> and the normal value to: Register your pass by tapping this link: {psRegisterURL}

PassSource Additional Properties

Our templates allow the setting of additional properties that are not included in the pass itself so that you can have hidden/private values.

Additional fields have a key and a value which can be set to be user editable. The key can be used wherever we use API paths but the values are generally hidden from users. You can use these fields to build databases and applications on top of the PassSource platform without having to host your own database and when combined with PassSource Triggers, many common workflows can be created without any custom code or services.

You can add any keys except keys that are already used by the pass (such as barcode, backgroundColor, logoText, coupon, etc.). They must be unique which is why we suggest using prefixes to identify your keys.

We have pre-defined several special keys that add additional functionality if set as additional parameters:

psPassDescriptionIf set, this will be used in pass lists and on the editor page. If this is not set, we'll set it for you, so you can use this value even if it isn't set up as an additional field. This is also used as the descriptive label in the Pass Scanner app.
psPathMigrationsA JSON object mapping old paths to new paths so if you decide to move structure_auxilliaryFields_myField_value to structure_secondaryFields_myNewField_value, you can specify this map so user's data will properly migrate when updated or fetched: {"structure_auxilliaryFields_myField_value": "structure_secondaryFields_myNewField_value"}
psScanColorA color value for the background when using our Pass Scanner app.
psScanTextThe text to display when using our Pass Scanner app.
psInformationURLA url that can be accessed by pressing the "more information" button when using our Pass Scanner app.
psInformationLabelIf you'd like to override the "more information" text in the button, you may use this field to do so. This feature is available using the scan.php feature or newer versions of our Pass Scanner app.
psDisplayURLA url to a page that will be displayed upon scan with our Pass Scanner app. The page will be displayed after any onScan triggers are processed.
psRegistrationMessageTo further customize the user's registration experience, this value will appear at the top of the registration form and may include HTML.
psRegisteredMessageThis appears on the page that appears after the user registers or updates their pass and may include HTML. Set this value in an onRegister trigger to provide custom messages based on the user's registration data.
psEditorPathsA comma-separated list of paths to use with our editor tool. We suggest setting the psInformationURL to {psEditorURL} to use this editor feature in our Pass Scanner app.
psEditCodeAllows specifying a code that can be used to edit passes for a specific template without having the clientHash. If this is specified in the template, convenience URLs (like psEditorURL) will include this an the template ID instead of your clientHash to restrict authentication based on a template. Having the psEditCode and the template ID, someone could edit the values of a pass but cannot make changes to the template or edit the values of passes based on other templates. If this is present, there will be an additional "Configure Pass Scanner App" button in the PassSource Settings for the template.
psEditorHeaderHTML text to customize the appearance of the editor page. Defaults to <h2>{psButtons}{psPassDescription}</h2> (note psButtons is not a normal magic string but is replaced with the appropriate buttons for this page.
psPortalHeaderHTML text to customize the appearance of the portal page. Defaults to <h2>Template Information</h2>
psPortalUpdatePathsA comma-separated list of paths that you want to expose on the portal page for quick updates to the template. It's like your own personal registration form for the template!
psExportPathsA comma-separated list of paths to use with our Batch Export tool.
psTriggerErrorSet this value to a string to stop execution of any triggers, not mark the pass as registered, and display the error to the user. The user can go back to the registration page to correct the error, so provide a useful message. This field will automatically be cleared and reset at the beginning of any trigger execution and does not need to be set up as an additional field in your template.

Registration pages

Our famous registration pages have gotten even better! You can create dropdowns and checkboxes for users to fill out and additional fields can also be set up for user registration. Validation is performed on registration fields to ensure that required fields are filled out and in the correct format. When the user registers, we automatically flag the pass as registered and execute any onRegister triggers you have set up. Further, you can customize the registration page and the registered pages using PassSource additional fields.

To make fields user editable, in the template editor, click the (i) button next to the field and check the User Editable box.

To enable registration, you will have to provide users with the templateHash or make the template public. Having the templateHash without the clientHash only allows users to edit user editable fields. If no user editable fields exist, the registration page will automatically re-direct to the creation page.

You may automatically pre-fill user editable fields by setting the values as GET parameters in the URL to the creation page. This page also supports sending the values via POST or encapsulated as JSON.

To take people to a registration page to update their pass, simply direct them to {psRegisterURL} on the back of the pass. Use the psRegistrationMessage and psRegisteredMessage additional properties to customize the registration and registered pages.

Note that if you assign the value to a container path using the API (for example, setting the barcode or structure_headerFields), and any of the sub-fields are user editable, accessing the registration page of a pass will automatically assign the user editable values and remove the override value of the pass so that the user can edit the information again.


You can add validation to user editable fields. Validation will use one of our pre-coded validators to verify that the user-submitted information is valid. The Validation field should be a comma separated list of validators without any spaces. With the exception of VRequired, the validators are not applied to an empty string.

The available validators are:

VRequiredMakes sure the value is set to something.
VEmailChecks to make sure the value is a properly formatted email address
VDateMust be a properly formatted date, but can be anything PHP stringtotime function will interpret.
VPhoneA properly formatted phone number. This must be only a numeric number but +,x() characters are okay.
VNumericMust be able to be converted to a number.
VAlphaOnly a-z and A-Z are supported. No special characters or numbers.
VAlphaNumericOnly a-zA-Z0-9 are supported.
VDecimalMust be able to be parsed as a decimal digit. Uses PHP is_float function.
VIntegerMust be an integer number.
VStateCodeMust be a valid US State code.
VZipMust be numeric (but can have -) and be 5-10 digits (not including the -)
VTrueMust evaluate to boolean true (typically used with Checkboxes).
VFalseMust evaluate to boolean false (typically used with Checkboxes).

Pass Editor

We've always had some simple tools for editing passes from our Pass Scanner app, but now it's even easier to customize this page for your individual needs. Simply enter the API paths to the fields you want to edit as an additional field named psEditorPaths.

You can get to the pass editor via the following link:{hashedSerialNumber}&clientHash={clientHash} We suggest including this path as the value of the psInformationURL additional field when using the Pass Scanner app (the clientHash should be safe to include here the API that exposes this for the Pass Scanner App requires authentication. You can also use {psEditorURL} magic string to automatically expand this URL and it will include the client hash or the templateId and psEditCode if set).

Template Portal

Professional accounts now have an easy way to view template stats and drill down to lists of individual passes. You can even expose fields here for quick template updates to push to all the passes. For example, if you have a marketing message you edit to push notifications to users, you could expose that field here for quick editing without going through the template editor. Similar to the editor, simply enter the API paths to the fields you want to edit as an additional field named psPortalUpdatePaths. Note that unlike the editor, these updates will be applied to the master template and then a push update will be sent to all installed passes.

Batch Create Tool

We have a new tool for quickly creating multiple passes by uploading a CSV file. The file should contain a templateId column indicating the template you'd like to use, and the other column headings should be API paths that you want to set in the template.

The tool will generate the creation links you can send via email or create the passes and append a link or hashedSerialNumber column to each row. You can also simply specify a number of passes to create from a template and return a list of hashed serial numbers. If links are generated, they will be automatically shortened and obfuscated to make it harder for end users to tweak the links (which shouldn't matter since the fields are all user editable anyways).

If you want an even shorter link, you can replace "" with "" however, these links will not work with the Apple Wallet scanner if used to generate a QR code since they will no longer be HTTPS links.

We've provided an example file that modifies the logoText, barcode_altText, and background color for a generic pass (you will need to copy the generic pass and use your template ID to test).

Batch Export Tool

Professional accounts now have an easy way to export the pass data for a template. It's flexible so that you can get exactly the data you need and you can build up custom fields and information using our additional and path features. There will be a Export Data button on the template portal if a psExportPaths additional field is present. This will download a CSV file with the requested data with one row per pass. Note that for performance reasons, the tool will only download in batches of 1000 and will order based on creation. To fetch more than 1000, add &start=START_INDEX to the URL where START_INDEX is the row you want to start with (for example, to fetch page 2, set START_INDEX to 1000).

Whitelabel services

If you have a reseller account, you can specify a logo and color that will be used to brand the entire site. Pages will not include any PassSource branding and ads will be hidden. If you're interested in setting up a reseller account, please contact us.

You can also include a psDashboard value in the client's additional JSON with a map of labels to URLs. This will add additional menu options on the client's dashboard. If the URL does not contain http, it will automatically be prefixed with

PassSource Conditions

Apple Wallet fields and the barcode can be set to display conditionally based on certain criteria. The field/barcode will only be included on the pass if the conditions evaluate to true. This can be useful if you only want something to be on the pass some of the time, but not all the time. For example, you might want to show a deal only after the pass has been scanned.

To specify conditions, click the (i) button for the field to disclose the advanced options and you will see a PassSource Conditions field.

Conditions can also be used to selectively execute triggers.

You may specify conditions using the following grammar:

<boolean> → AND
<boolean> → OR
<comparator> → !<comparator>allows testing X <= Y by doing !(X > Y)
<comparator> → =
<comparator> → >
<comparator> → <
<test> → isEmptyis 0 or false or "" or null
<test> → isSetis not null
<test> → !<test>
<magic> → {magic}a magic string that will be evaluated and the evaluated value will be used for tests
<valueString> → <magic>
<valueString> → a number
<valueString> → a boolean value
<valueString> → a string valuea string should be denoted by surrounding in double quotes
<conditionString> → <valueString>
<conditionString> → <valueString> <test>
<conditionString> → registered | scanned | deleted | installedregistered, scanned, deleted, and installed are special keywords that are evaluated only if present
<conditionString> → !<conditionString>for negating a condition
<conditionString> → (<conditionString>)for grouping conditions and nesting evaluation
<conditionString> → <conditionString> <boolean> <conditionString>for joining multiple conditions
<conditionString> → <valueString> <comparator> <valueString>if either valueString is a string, the values are compared as strings, otherwise they are compared numericly

See below for examples.

PassSource Triggers

Triggers are a powerful new feature exclusive to PassSource that allows you to build complex workflows without writing a single line of code. Triggers allow you to hook into events like pass registration, scanning, and updates. PassSource logs these events for the lifecycle of a pass, and with triggers, you can get pass updates, make changes to a pass, or more deeply integrate with a custom service exactly when you want to. Currently, the trigger action is defined as a JSON dictionary, but we will be adding a more friendly visual editor in the future.

The following is a list of access types and their corresponding trigger keys:

Trigger and ValueWhen Logged
onCheck 0Triggered by a call to the trackPassAccess API (which is called by the Pass Scanner app).
onCreate 1When the serial number is generated for a pass (guaranteed to execute exactly once per pass).
onInstall 2Logged by the web service whenever a pass is installed on a device. Repeated installs or installs on other devices will log additional entries. Triggers onInstall triggers regardless if the pass has already been installed.
onDeviceUpdate 3Logged when user invokes a manual update by doing the pull-to-refresh on the back of the pass. To prevent issues, additional requests within 30 seconds are ignored.
onRegister 4This is called if the registration form is submitted. Add the condition !registered to only execute the first time the registration form is submitted.
n/a 5Logged by the updatePassesForTemplate and pushPassUpdate API calls. The former is used by the "Update All Passes" button on the template editor and the template portal when submitting exposed fields. There are no associated triggers as this is not a user-driven event.
onDelete 6Logged when the user deletes a pass from a device. Note that there is no guarantee that this will be called when a pass is deleted and should not be depended on for determinining if a user has a pass installed or not.
onScan 7Triggered by a call to the trackPassAccess API (which is called by the Pass Scanner app).
onEdit 8Triggered when submitting the editor form. Use to automatically process pass before sending updates to the user.

When a trigger is encountered, it looks through the template for a set of actions and executes them in order. Each trigger action should be a dictionary with an action key and some additional keys depending on the action. The following lists the valid actions and thier properties:

ActionAdditional Keys and Description
urlmagic strings will be replaced and URL encoded
Makes a request to the specified URL. You can use this to call out to web services or even make PassSource API calls. The results of the request are ignored. If there is a problem, use the API to set the psTriggerError additional value of the pass to a string. If this is set, no further triggers will be executed and the event will not be logged. If this is done in an onRegister trigger, the error will be displayed to the user.
targetPathan API path
valuethe new value to set (magic will be applied)
Sets the value of the field at targetPath to value.
targetPathan API path
amountthe amount to increment the value (specify a negative number to decrement)
Increments the value of the field by amount. The field will be forced to a number if it is not already. You can also use this to decrement a field by passing a negative value.
targetPathan API path to a field with a JSON array of triggers
This can be used to run a set of triggers which you may want to call from multiple triggers (like onCreate, onRegister, and onEdit). Think of this like running a sub-routine of triggers. The value of this field should be a valid JSON array of triggers. Example
In addition to the listed keys, all triggers also support a PSConditions key to specify conditions that will be evaluated to determine if trigger is executed or skipped.

To see an example of how a trigger action JSON dictionary is written, check out our examples. A simple one changes the color of a pass when scanned.

Technical Details

Getting Started

Getting started with the API is simple!

  1. Sign up for a professional account.
  2. Get your client hash from your advanced settings page.
  3. Start creating and updating passes using API links!

See our examples and tutorials for some ideas.

Creating Passes via Links

This is the easiest way to make changes to templates without having to worry about the "API". In fact, this was the primary method for making changes and is still supported with the old login API, the new login API, or the clientHash.

You can send links to users with their information pre-filled so that you don't have to pre-generate passes.

This method is particularly useful if you already have an email program that you can insert fields from your database into. It does not require any web server or backend to manage your passes so it is the easiest solution for restaurants distributing loyalty cards or coupons. Only user-editable fields can be overwritten, so it's easy and convenient way to pre-fill data for users. If you don't want users to be able to edit their data, you will probably want to use the API to pre-generate fixed passes instead.

Before you create your pass link, you will want to get the templateHash. This can be found on the template editor under PassSource options.

Once you have your template hash, to create the pass link, just construct a link as follows:{templateHash}&{apiPaths} The apiPaths are any number of key value pairs where the key is an API path and the value is the URL encoded value to set.

You may also overwrite and specify images by using the key images_ plus the image name and the value to a URL encoded URL to the image. For example, you could add the following to change out the logo: & The possible image keys are as follows. Note that not all pass types support all image types. For more information, check out Apple's documentation (you may need an Apple developer account to access). images_icon images_logo images_thumbnail images_strip images_background images_footer You may add "@2x" to the end of any of those to specifically target the high resolution version and we recommend setting both the normal and the @2x versions. We will automatically scale the images to be the optimal size, so you can use the same path for both the @2x and normal versions.

You can also pre-generate passes and then link to the pass using the hashedSerialNumber. This is a good method for creating store-cards and other items where you would rather the user not be able to modify the values themselves. The first step is to add the user's custom fields in the same manner as the clear-text pass links and include your clientHash or simply use the API. If you're using the create page, you can add &generate=true to the URL to have it show the hashedSerialNumber instead of a page with the pass or downloading the pass. However, we recommend using the createPassFromTemplateFields API call as you will be guaranteed a JSON response even if there is a problem.

The hashedSerialNumber is a string representing the serial number for this pass. You can store this in your database as you will use this for any updates and tracking of this pass. When you want to give this pass to the user, simply direct them to the following URL:{hashedSerialNumber} This link will display a page with the pass and a link to download unless they are on an iPhone or iPod touch in which case it will simply prompt the user to add the pass to their Apple Wallet.

Why hash the serial number? The serial number is not secured for the user since they can obviously open up the pass file to get that. The reason we hash the serial number is it adds an additional level of complexity. Since anyone can download any pass by just having the serial number, hashing it makes brute-force guessing of serial numbers that much more difficult.

Getting the pass file

Typically you'll be linking to passes using the hashedSerialNumber as passing around large data files isn't very efficient, but if you have an iOS native app or you have to have the pass data, you can download the Apple Wallet pass file.

To download the pass file, add &download=true to the create URL. This acts the same as the generate parameter with the difference that instead of returning the serial number, it will return the pass itself. If you need the hashedSerialNumber, do the generate command and then use the user's create link with the download parameter to get the pass data.

Client Hash

We now have a stateless API that uses a token for authentication instead of requiring logins and cookies. We call this authentication token your clientHash. This is a unique key that is specific to your account and is used in all your API calls to validate that you have permission to perform the action. It is based on your account ID, email, password, and subscription status, so if any of these values change, so will your clientHash (so if you ever need to invalidate a client hash, simply change your password). It is important that you do not share your clientHash and make sure it is not publicly viewable by not including the magic string "{clientHash}" in public/visible fields in the template.

You can use the login API function to get your clientHash, or you can simply copy it from your advanced settings page.


Pretty much everything is based on templates. You can use our website to create templates to customize passes to your liking. This will be your first step in designing and testing passes you will customize for your users.

Go ahead and create some templates and try out the passes on your test device to see how they look. Once they look right, you can move on to creating passes for your users.

Public passes are branded with a link back to and are shareable.

General Philosophy

We have designed our API to be simple to use and simple to test. We wanted to allow companies to send an email blast that could contain links with embedded personal information to easily create personalized passes for their users. We also wanted developers to be able to easily test the API with just a web browser without having to write complicated code or use any specialized frameworks.

API functions can be called by simply constructing a URL with the following format:{apiFunctionName}.php?clientHash={clientHash}&{parameters} Most of the API calls expect data to be passed as simple HTML GET parameters, however, for functions that accept large amounts of data, you can also send JSON objects via HTML POST with the key "JSON" (this is also useful if you have any array data). Functions that support POST upload are indicated in the table. The clientHash and templateHash parameters should always be sent via GET for authentication.

All API calls return a JSON object with at least a success key that may be true or false. If it is false, there will be a key message that will contain the error message.

API Functions

functionparameters, description, and returns
emailaccount email
passwordaccount password
Logs in and gets your clientHash (also sets session cookies for editor page or other interface pages).
clientHashYour clientHash token.
logout Logs you out and clears the session cookies. Client hash not required.
clientHashclientHash for authentication
Validates that this is a valid client hash and returns client account information.
clientNameThe name set when you registered.
clientIdYour client ID.
emailThe email address on file.
clientTypeThe type of client. Since this requires the API, this value should always be 2 (professional account).
clientHashSame value passed in for reference.
expiresThe time when your subscription is set to expire.
additionalThe value set in the additional JSON field of your advanced settings.
whitelabeltrue or false depending on if whitelabel services are enabled.
referenceIdIf this is a managed account, this will be the ID of the managing account. Otherwise, 0.
backgroundColorIf whitelabelled, this is the custom background color set for the account used for interface customization.
passTypeIdThe pass type identifier (for creating passes manually).
teamIdentifierThe team identifier (for creating passes manually).
certificatePasswordThe certificate password (for creating passes manually).
clientHashclientHash for authentication
Returns all templates for this client. In addition to the templateInfo fields, we also provide a url key that will point to the template portal page.
templatesAn array of template objects (see templateInfo for the structure).
clientHashclientHash for authentication
templateHashThe template hash (can be found in the PassSource options of the template editor).
Returns information about a template, including what you would need to submit modifications to insertUpdateTemplate. In addition to the fields below, it also includes the same information from clientInfo for the template owner (which may not match the clientHash passed for authentication if you have a manager account).
templateIdThe template ID.
templateNameThe template name.
templatePublictrue if the template is marked as public or false.
passConstructorThis is a structured array that contains all the information to build a template. If you plan on using this, please contact us.
templateUpdatedThe timestamp when the template was last updated.
templateHashThe hash for this template (for public edits and creation URLs).
clientHashclientHash for authentication
templateHashThe template hash (can be found in the PassSource options of the template editor).
Returns statistics for the template. If you have more than 500 passes generated for a template, the stats will require manual updates as they will take some time to generate.
createdThe number of passes created.
installedThe number of passes installed.
deletedThe number of passes deleted.
theoreticalThe number of passes theoretically installed (installed - deleted).
scannedThe number of passes scanned.
registeredThe number of passes registered.
ageThe age in seconds of the oldest stat. Will always be 0 for small data sets.
clientHashclientHash for authentication
templateHashThe template hash (can be found in the PassSource options of the template editor).
accessTypeThe accessType you wish to get passes for.
(optional) countThe number of passes to return. -1 is the default and will fetch all passes.
(optional) startThe index of the pass to start counting from (for pagination).
Returns a list of passes that match the accessType. Each object in the list contains the hashedSerialNumber and the userFields.
passesArray of pass objects.
clientHashclientHash for authentication
templateHashThe template hash (can be found in the PassSource options of the template editor).
Sends a push notification to all installed passes with the current information. Use after changing the template.
countThe number of passes updated.
insertUpdateTemplate POST data supported (clientHash and templateHash parameters should be sent via GET)
clientHashclientHash for authentication
templateNameThe name to assign to the template.
templatePublictrue if you want to make this template publicly available or false.
passConstructorA structured array with the template information. You should be able to use an existing pass json as a base.
templateHashThe template hash of the existing pass or the templateHash of a template to copy.
(optional) templateIdThe existing template ID. Must match the templateHash if provided.
Creates a new template or updates an existing template.
templateHashThe template hash for the template.
templateIdThe template ID for the template.
uploadTemplateImages POST data supported (clientHash and templateHash parameters should be sent via GET)
clientHashclientHash for authentication
templateHashThe template hash (can be found in the PassSource options of the template editor).
icon, logo, etc.Any image names are supported and should contain either the raw binary image data or a URL to an image. Can also be set to the string "DELETE" to remove an existing image.
Uploads or deletes the specified images for the template replacing any existing images.
clientHashclientHash for authentication
templateHashThe template hash (can be found in the PassSource options of the template editor).
Deletes a template and all associated passes and tracking from the database.
deletedTemplateIdThe template ID of the deleted template.
createPassFromTemplateFields POST data supported (clientHash and templateHash parameters should be sent via GET)
clientHashclientHash for authentication. This is optional, but if this clientHash does not have access to the template or is missing, only user editable fields will be updated and other values will be ignored.
templateHashThe template hash (can be found in the PassSource options of the template editor).
API pathsAPI paths can be added to set these values on the pass.
Creates a pass from the specified template and initializes the userFields with any provided API paths. You can pass these same values to to see the pass rendered instead of getting a JSON response.
hashedSerialNumberThe hashedSerialNumber for the created pass.
clientHashclientHash for authentication
hashedSerialNumberThe hashedSerialNumber for the pass.
Fetches the data for the pass. Includes the template information in addition to the below fields.
hashedSerialNumberSame as provided value.
userFieldsA JSON object with the override keys and values.
clientHashclientHash for authentication
hashedSerialNumberThe hashedSerialNumber for the pass.
Fetches a list of all the tracking events that have happened for this pass. Each event is an object with an accessType key and a time key.
trackingArray of events.
clientHashclientHash for authentication
hashedSerialNumberThe hashedSerialNumber for the pass.
accessTypeThe accessType event to log.
Logs a specified accessType for a pass. If accessType is a check or scan, the return json may include the following keys:
updatedTrue if the triggers caused the pass to be modified and an update pushed, false if not.
scanTextText to display on the scanner. This is evaluated from psScanText so set this value to customize.
scanColorThe color for the scanner background (in RGB, color name, or hex). This is evaluated from psScanColor which can be set to customize the interface.
descriptionA description of the pass. This is evaluated from psPassDescription so set this value to customize.
informationURLA URL to make edits to the pass. This is evaluated from psInformationURL so set this value to customize.
informationLabelThe text to use for the button in the scanner interface when informationURL is present. This is evaluated from psInformationLabel so set this value to customize.
displayURLA URL to display instead of the normal scanner interface. This is evaluated from psDisplayURL so set this value to customize.
clientHashclientHash for authentication
hashedSerialNumberThe hashedSerialNumber for the pass.
accessTypeThe accessType event test.
For determining whether or not the specified event has been logged for a pass.
checktrue if the event has been logged, false if not.
lastThe timestamp for the last occurrence of the event. Only present if check is true.
updatePassFields POST data supported (clientHash and hashedSerialNumber parameters should be sent via GET)
clientHashclientHash for authentication. This is optional, but if this clientHash does not have access to the template or is missing, only user editable fields will be updated and other values will be ignored.
hashedSerialNumberThe hashedSerialNumber for the pass.
psReplaceAllIf this is set to true, all existing fields will be replaced (and any fields missing will be deleted). Otherwise, this will just update any existing fields.
API pathsAPI paths can be added to set these values on the pass. If you provide the client hash, provide all fields that you want to store for the pass as this will replace the entire set of existing fields if psReplaceAll is set.
Updates the specified fields for a pass. You can pass these same values to to see the pass rendered instead of getting a JSON response. If clientHash is provided and psReplaceAll is set, this will replace entire set of existing fields. If clientHash is not provided, will replace all user editable fields (deleting fields that are user editable that are not present if psReplaceAll set).
updatedtrue if the pass was updated (including updating images), false if not (if no values actually changed).
clientHashclientHash for authentication
hashedSerialNumberThe hashedSerialNumber for the pass.
Sends a push notification for this pass with the current information. Use after making changes like after updatePassFields (the changes above are not automatically pushed in case you are using from a trigger or you need to make multiple saves).
clientHashclientHash for authentication
hashedSerialNumberThe hashedSerialNumber for the pass.
Deletes the pass from the database. Future attempts to update or fetch this pass will fail. Only use to remove test data in case user still has link to the pass or has pass installed.
imageForNameTemplateHash Either provide the templateHash or the hashedSerialNumber
imageThe name of the desired image.
(optional) templateHashThe template hash (can be found in the PassSource options of the template editor).
(optional) hashedSerialNumberThe hashedSerialNumber for the pass.
Gets the URL for the specified image if it exists (will not succeed if image does not exist).
urlThe URL to the named image.

Pass Scanner app

Our Pass Scanner app (free on the App Store) can be used as an end-to-end solution to scan and manage your Apple Wallet passes.

The app can be set to display the encoded data (for copying or simply viewing), or it can pass the barcode data as a get parameter (message)to any URL, or it can run PassSource triggers to track the scan and automatically perform actions.

When using the custom URL mode, the get parameter message will be added to the custom URL with the barcode data as a string. The app then opens a web-view with that URL where you can perform custom actions and create your own interface.

To automatically enable custom URL mode, you can visit the following configuration URL on the device with the Pass Scanner app installed: passscanner://?customURL={your custom url URL encoded}

The flash in the app turns on automatically if there isn't enough light. Make sure the phone is not resting on the table when you start the app and there is enough light in the room and the flash should not engage.

The app is designed not to go to sleep while the scanner is visible, so we recommend keeping the device plugged in if you are going to set this up near a register.

In PassScan mode, it will automatically return to scanning screen after 5 seconds unless you tap anywhere on the screen.

To automatically set the iBeacon parameters for the app, use a URL in the format: passscanner://?proximityUUID={proximityUUID}&major={major}&minor={minor}

You can use this link to set up the app to be a a beacon for our demo passes.

Changes and Notes

Please note that we've made a lot of upgrades since our initial release of PassSource in 2012. We've done our best to maintain backwards compatibility with previous versions of our API, but if you find that we missed something, please let us know! Over time, we will eventually remove the older API hooks, but we've checked how people are using things and most of the things we've deprecated weren't being used and we've replaced them with more generic and powerful features.

We've re-written the entire back-end to be much more modular, efficient, and flexible with increased whitelabel support across the board. We have even created some PHP classes you can drop-in to your code to make things even easier (which was quite a feat as our API was already probably the easiest out there). One of the main reasons for the new APIs was to make custom solutions easier for us and our clients and most of the new site has been built on top of the API, so it should be fairly comprehensive.

We've also completely re-designed our front-end to better match newer design sensibilities and to allow complete re-branding of most of the site should you need to whitelabel.

We have simplified things across the board and made things consistent and made the most requested features even easier to implement via new dashboards and portal pages.

Latest Highlights

We will demo new features on our new beta site before pushing changes live, so if you ever need to test in a playground environment, you can use that server to make destructive edits or test the API or features. Periodically, we will replace the account and template data on the beta server with the live server values, however, passes and tracking may not be synced. Feel free to contact us about the use of the beta server. The beta site can be found at:

Automatic Purging

Tracking data and passes that haven't been updated in over 2 years may automatically be purged from our system. Additionally, passes that have no device or access tracking data (passes that have not been accessed or installed besides their initial creation) will be purged after 6 months.

If you think this may be an issue or if you have a pass that may have been purged that you need, please contact us.

Constructing Templates Manually

You can use our PassSource.php classes to update templates or you can update the code manually via the API.

This part of the API starts getting pretty complex, so if you'd like our help in doing something, please drop us a line.

All templates are built on a template structure which is simply a JSON object that defines information about a pass and indicates user editable fields. It's purposefully designed to be very similar to Apple's pass JSON structure and in fact you could take the manifest.json from a pass to create a new template.

A field can consist of the value or, more commonly, will be a PSAttribute JSON object which will have the following keys:

PSValueThe actual value.
PSEditableWILL BE DEPRECATED! If you are using this, let us know and we'll make sure your code migrates. We will be moving to a psRegistrationPaths field similar to psEditorPaths to allow for ordering of fields which can't be done with PSEditable. Will also add consistency. Indicates that this field should appear on the registration form and can be set via URL parameters. Editable fields may have the following additional properties:
PSLabelThis will be used when the field is displayed on the registration, editor, or portal forms. By default, this will be the path to the field.
PSAttributeTypeBy default, most fields are just text, but you can have special editors. Currently we support PSAttributeTypeText, PSAttributeTypeDropdown, PSAttributeTypeMultiselect, PSAttributeTypeCheckbox, PSAttributeTypeColor, PSAttributeTypeStepper. We will be adding a date picker and time picker and location picker soon.
PSOptionsYou can specify a set of options that will appear as a dropdown on the registration form. They "keys" of this JSON dictionary should be the labels and the "values" should be the value that will be set.
PSStepAmountIf the PSAttributeType is PSAttributeTypeStepper, this value indicates the amount to increment or decrement by. This is mainly for conversion from the legacy PassScan increment option.

Examples and Tutorials

Prompt a user to register.

Create a backField with the following value: Register your pass for additional benefits! {psRegisterURL} Set the attributedValue to: <a href="{psRegisterURL}">Register your pass</a> for additional value! Add the condition: !registered

Include a link to update registration.

Create a backField with the following value: Update your information: {psRegisterURL} Set the attributedValue to: <a href="{psRegisterURL}">Update your information</a> Add the condition: registered

Push notifications to installed users.

Create a backField with label "Latest News" and value set to your message.

Open the advanced options and note the API path. (example: structure_backFields_news_value)

Set the changeMessage in the advanced settings to "%@" (without the quotes).

Create an additional field with key psPortalUpdatePaths and value "structure_backFields_news_value" (without the quotes).

Go to the template portal page and enter in the new message to send to passes.

Setting the geolocations for a pass.

The locations value can be set using the JSON format specified by Apple. For example, to set the locations to the Eiffel Tower, the Empire State building, and the Statue of Liberty, the JSON would be: [ { "longitude":48.8583701, "latitude":2.2944813, "relevantText":"Welcome to the Eiffel Tower!" }, { "longitude":40.7484444, "latitude":-73.9878441, "altitude":381, "relevantText":"Welcome to the 102nd floor of the Empire State Building!" }, { "longitude":40.6892534, "latitude":-74.0466891, "relevantText":"Welcome to the Statue of Liberty!" } ]

The JSON needs to be URL encoded to pass it as a parameter using the URL API. You can do this online using our encoding tool.

The encoded result is: %5B%0A%09%7B%0A%09%09%22longetude%22%3A48.8583701%2C%0A%09%09%22latitude%22%3A2.2944813%2C%0A%09%09%22relevantText%22%3A%22Welcome%20to%20the%20Eiffel%20Tower!%22%0A%09%7D%2C%0A%09%7B%0A%09%09%22longitude%22%3A40.7484444%2C%0A%09%09%22latitude%22%3A-73.9878441%2C%0A%09%09%22altitude%22%3A381%2C%0A%09%09%22relevantText%22%3A%22Welcome%20to%20the%20102nd%20floor%20of%20the%20Empire%20State%20Building!%22%0A%09%7D%2C%0A%09%7B%0A%09%09%22longitude%22%3A40.6892534%2C%0A%09%09%22latitude%22%3A-74.0466891%2C%0A%09%09%22relevantText%22%3A%22Welcome%20to%20the%20Statue%20of%20Liberty!%22%0A%09%7D%0A%5D%0A

This link will create a demo pass with the locations automatically set:!%22%0A%09%7D%2C%0A%09%7B%0A%09%09%22longitude%22%3A40.7484444%2C%0A%09%09%22latitude%22%3A-73.9878441%2C%0A%09%09%22altitude%22%3A381%2C%0A%09%09%22relevantText%22%3A%22Welcome%20to%20the%20102nd%20floor%20of%20the%20Empire%20State%20Building!%22%0A%09%7D%2C%0A%09%7B%0A%09%09%22longitude%22%3A40.6892534%2C%0A%09%09%22latitude%22%3A-74.0466891%2C%0A%09%09%22relevantText%22%3A%22Welcome%20to%20the%20Statue%20of%20Liberty!%22%0A%09%7D%0A%5D%0A

Change the color of a pass when scanned.

Add an onScan trigger: {"action":"PSActionSetValue","targetPath":"backgroundColor","value":"blue"}

Add 25 points to a header field after registering the pass.

Go into your template and note the API path to the field (for our example, we'll use structure_headerFields_points_value).

Add an onRegister trigger (note we added a condition to make sure the points only get granted once): {"action":"PSActionIncrementValue","targetPath":"structure_headerFields_points_value","amount":25,"PSConditions":"!registered"}

Set scan output based on previous scan.

This sets this scan display values based on whether the pass has been scanned or not for use with our Pass Scanner app.

Add an additional field named subtriggers with the following value: [ { "action" : "PSActionSetValue", "targetPath" : "psScanColor", "value" : "{PSColorGreen}" }, { "action" : "PSActionSetValue", "targetPath" : "psScanText", "value" : "First Scan" }, { "action" : "PSActionSetValue", "targetPath" : "psScanColor", "value" : "{PSColorYellow}", "PSConditions" : "scanned" }, { "action" : "PSActionSetValue", "targetPath" : "psScanText", "value" : "Already Scanned", "PSConditions" : "scanned" } ]

Set both the onCheck and onScan triggers to: { "action": "PSActionExecuteTriggers", "targetPath": "subtriggers" }

Only show field if the value is not empty.

For a backfield with a value path of structure_backFields_myKey_value, set the conditions of the entire field to: {structure_backFields_myKey_value} !isEmpty

Only show field if the points value is greater than 20.

Assuming the points field path is structure_headerFields_points_value, set the conditions of the field to: {structure_headerFields_points_value} > 20

Only show field if the secondary name field is equal to "PassSource".

Assuming the field path structure_secondaryFields_name_value, set the conditions of the field to: {structure_secondaryFields_name_value} = "PassSource"

Only show field if the pass has been scanned.

Set the conditions of the field to: scanned

Show field until the pass is registered.

Set the conditions of the field to: !registered

Customize how passes are displayed in lists.

To have the pass show the name and points in lists and for the scanner and editor descriptions, create an additional field with key psPassDescription and set it to: {structure_secondaryFields_name_value} has {structure_headerFields_points_value} points

Create a barcode that can be used to install the pass as well as for the Pass Scanner app.

The newest version fo the Pass Scanner app will automatically identify hashes within a URL, so you can simply set the barcode message to {rootPath}/pass/create.php?hashedSerialNumber={hashedSerialNumber} and the code can be scanned to get the pass as well as be used to update the pass.

QR Code Generator is a great site for generating QR code images that can be printed on physical cards. Use the templateHash to create a link to generate a new pass with each scan, or use the hashedSerialNumber to generate a code for a specific pass.

Add 1 point to a header field whenever the pass is scanned.

Go into your template and note the API path to the field (for our example, we'll use structure_headerFields_points_value).

Add an onScan trigger: {"action":"PSActionIncrementValue","targetPath":"structure_headerFields_points_value","amount":1}

Set the barcode message, altText, and member name for a new pass via an emailed link.

First you need the templateHash for the template and make sure the barcode message, altText, and member name are all user editable (click the (i) button next to the field and check the User Editable box.)

For our example, we're setting the barcode message and altText to "9991212", and the member name (which is a primary field) to "George P. Burdell".

Don't forget to URL encode the values. You could use this method to distribute customized passes to a mailing list with each person's email containing a link to a pass with their name and member ID pre-filled so all they have to do is tap the link and tap add to get it in their Apple Wallet. You could add additional user-editable fields and direct to the registration page instead of the create page if you wanted to capture additional information.

Construct the link as follows:,&barcode_message=9991212&barcode_altText=9991212&structure_primaryFields_member_value=George%20P.%20Burdell

Get your clientHash from the API.

Go to the following link:{email}&password={password} then extract the clientHash parameter from the returned JSON.

Create a loyalty card with automatic redemption.

Create a coupon card (for our example, we're using our PassSource loyalty demo), then set up the following triggers to set up the automatic actions during a scan:

You can further enhance the experience by having different fields appear depending on if the pass is a coupon or a storeCard, so that you can indicate what will happen when it is scanned or change out the offer.

Use a web widget to allow users to create passes for their cards.

This widget will create a generic pass with the user-entered member number as the barcode message: <form method="get" action=""> <input type="hidden" name="templateHash" value="eNortjIysVIqLA00jIiyyC0pMXKOcPYqyrIozC4ItLVVsgZcMKPxCfk," /> <label>Enter your member number:</label> <input type="text" name="barcode_message" /> <input type="submit" value="Get Pass" /> </form>

Create a pass in iOS and prompt user to add to Apple Wallet.

This creates a pass setting the barcode message and altText and member name. #import <PassKit/PassKit.h> #define template_hash @"eNortjIysVIqLA00jIiyyC0pMXKOcPYqyrIozC4ItLVVsgZcMKPxCfk," // you'll want to include your client hash if you're not just modifying user editable fields. // do the following in a UIViewController // run asynchronously to not block main thread dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // create pass with template NSString *passURL = [NSString stringWithFormat:@"", template_hash]; NSLog(@"Loading pass from URL: %@", passURL); NSData *passData = [NSData dataWithContentsOfURL:[NSURL URLWithString:passURL]]; PKPass *pass = [[PKPass alloc] initWithData:passData error:&error]; if (pass == nil) { NSLog(@"Error creating pass: %@", error); } else { dispatch_async( dispatch_get_main_queue(), ^{ PKAddPassesViewController *apvc = [[PKAddPassesViewController alloc] initWithPass:pass]; [self presentViewController:apvc animated:YES completion:nil]; }); } } else { NSLog(@"There was a login error: %@", error); } });