Getting started
PassNinja is a turn-key service for creating and validating NFC enabled digital passes. NFC is a contactless technology that allows phones to authenticate themselves when they get near a terminal. Our RESTful API lets developers easily integrate NFC passes into their solutions.
The PassNinja API has predictable resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication and verbs.
Before using the PassNinja REST API, it is important that you understand the basics of RESTful web services and JSON representations.
Throughout these docs, you'll find helpful code samples below each section explanation. Code samples are available in multiple programming languages as outlined in the SDKs section below.
Parameter Reference
In this documentation, certain identifiers are represented using placeholders to ensure clarity and consistency across examples. These placeholders indicate where developers should substitute their own values while also highlighting the expected format.
| Placeholder | Description | Format | Example |
<YOUR_API_KEY> |
Represents your API key for authentication | <32-char hex> |
91dbb1e7af9c80aba6ed3f95a1545b4e |
<YOUR_ACCOUNT_ID> |
Represents a unique account identifier | aid_0x<hex> |
aid_0xa01 |
<YOUR_PASS_TYPE> |
Represents a pass type identifier | ptk_0x<hex> |
ptk_0x14 |
<SERIAL_NUMBER> |
Represents a unique pass identifier (also known as passId) | <18-char hex> |
838b8cf60dac2bfad9; |
SDKs / Libraries
We maintain libraries in popular scripting languages to make it easy to build on top of PassNinja. You can find the source code for these here:
- PassNinja Python library
- PassNinja Ruby gem
- PassNinja NPM package
- PassNinja Swift library
- PassNinja Java package
- PassNinja C# package
- PassNinja PHP Composer package
You can find the installation commands for each of these below.
pip install passninja
Authentication
Every API request must be authenticated. We use two custom HTTP headers for authentication. The first is an API key, the second is an account ID - both of these can be found in your account dashboard under pass template "send" page for a given pass in the Pass Templates tab. The API key should be sent in the X-API-KEY header and the Account ID should be sent in the X-ACCOUNT-ID header. See the Parameter Reference for format details.
You should only send traffic over HTTPs and do your best to keep your authentication credentials private.
If you use one of our ready-made SDKs, then you only need to set your keys during initialization.
# Authentication is done via HTTP headers
# X-API-KEY: Your API key
# X-ACCOUNT-ID: Your account ID
curl -X GET 'https://api.passninja.com/v1/passes' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>'
Pass Templates
Pass Templates are created from your account and customized with the pass template editor. They represent a template to create a pass from. Pass Templates have a pass template key that is present in the getting started tab for a given pass template, it takes the form of <YOUR_PASS_TYPE> and is required to be passed in when creating a pass.
Furthermore, pass templates allow you to define the JSON keys you will use to populate your pass upon creation.
List pass templates
Retrieves a list of all pass templates for your account, including metadata about each template such as the number of issued and installed passes.
This endpoint requires no parameters and returns an array of pass template objects.
•
id - The pass template key (e.g., <YOUR_PASS_TYPE>)•
name - Template name•
platform - Platform (apple or google)•
style - Pass style•
issuedPassCount - Total passes issued•
installedPassCount - Total passes installed•
createdAt - Creation timestamp•
updatedAt - Last update timestamp
curl -X GET 'https://api.passninja.com/v1/pass_templates' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>'
You will get a response with an array of pass template objects. Example response:
{
"pass_templates": [
{
"id": "<YOUR_PASS_TYPE>",
"name": "Loyalty Card",
"platform": "apple",
"style": "storeCard",
"issuedPassCount": 150,
"installedPassCount": 89,
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-03-20T14:45:00Z"
}
]
}
Get a pass template
Retrieves details about a specific pass template using its template ID.
Below is the required parameter for retrieving a pass template:
-
id* stringThe pass template key, present in the getting started tab for a given pass template. It looks like this:
<YOUR_PASS_TYPE>
•
id - The pass template key•
name - Template name•
platform - Platform (apple or google)•
style - Pass style•
issuedPassCount - Total passes issued•
installedPassCount - Total passes installed
curl -X GET 'https://api.passninja.com/v1/pass_templates/<YOUR_PASS_TYPE>' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>'
You will get a response with a pass template object. Example response:
{
"id": "<YOUR_PASS_TYPE>",
"name": "Loyalty Card",
"platform": "apple",
"style": "storeCard",
"issuedPassCount": 150,
"installedPassCount": 89
}
Create a new pass
Creating a pass allows you to create a new pass for a given pass template with given values. In addition to issuance, for an additional $0.05 you can send the pass via text message. Returns pass id (also known as a serial number), and when applicable message_status.
This creates an "Active pass" which incurs a monthly cost. Please see pricing for more info.
For self-serve customers, if you send text messages you will be rate limited to a maximum of 10 requests per second. For enterprise customers, this rate limit is 100 requests per second when sending passes via text message.
Below is a list of acceptable params for creating a pass. * denotes a required parameter:
-
passType* stringThis is the pass type key, it is present in the getting started tab for a given pass template. It looks like this:
<YOUR_PASS_TYPE> -
pass* objectThe keys for this object are defined in the pass ninja console, and can be found in the getting started tab for a given pass template.
-
recipient(optional) objectThe name, reason and phone number or email of the person you wish to issue this pass. The parameters here are NOT used to create passes, only to send them. Acceptable params are as follows:
-
full_name* stringThe name of the person receiving the pass.
-
reason* stringThe reason the person is receiving the pass. Never sent to user, only for compliance purposes.
-
sms(optional) stringInternationally formatted phone number to send message to, with a + in front. For example:
+15613437899 -
email(optional) stringRFC compliant email address to send message to. For example:
support@passninja.com
-
curl -X POST 'https://api.passninja.com/v1/passes' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>' \
-H 'Content-Type: application/json' \
-d '{
"passType": "<YOUR_PASS_TYPE>",
"pass": {
"discount": "50%",
"member-name": "John"
}
}'
You will get a response with the created pass object. Example response:
{
"serialNumber": "<SERIAL_NUMBER>",
"id": "<SERIAL_NUMBER>",
"urls": {
"landing": "https://i.installpass.es/p/<SERIAL_NUMBER>"
},
"passType": "<YOUR_PASS_TYPE>"
}
List passes
Allows you to retrieve a list of passes using it's pass template id.
Below is a list of required params for retrieving a pass:
-
passType(aka pass template id)* stringThis is the pass type key, it is present in the getting started tab for a given pass template. It looks like this:
<YOUR_PASS_TYPE>
•
serialNumber - The pass serial number•
id - Same as serialNumber•
urls.landing - Download URL for the pass•
passType - The pass template key•
issuedDate - When pass was created•
installedDate - When pass was installed (null if not installed)•
status - Pass status (Active, Removed, Expired, or N/A)
curl -X GET 'https://api.passninja.com/v1/passes/<YOUR_PASS_TYPE>' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>'
You will get a response with an array of pass objects. Example response:
{
"passes": [
{
"serialNumber": "<SERIAL_NUMBER>",
"id": "<SERIAL_NUMBER>",
"urls": {
"landing": "https://i.installpass.es/p/<SERIAL_NUMBER>"
},
"passType": "<YOUR_PASS_TYPE>",
"issuedDate": "2024-04-23T10:15:00Z",
"installedDate": "2024-04-23T14:30:00Z",
"status": "Active"
}
]
}
Get a pass
Allows you to retrieve a pass using it's pass type and pass id, also known as it's serial number.
Below is a list of required params for retrieving a pass:
-
passType* stringThis is the pass type key, it is present in the getting started tab for a given pass template. It looks like this:
<YOUR_PASS_TYPE> -
passId* stringPassId also known as a serial number. Takes on a namespaced format which looks like
<SERIAL_NUMBER>
•
serialNumber - The pass serial number•
id - Same as serialNumber•
pass - Object containing all pass field values•
urls.landing - Download URL for the pass•
passType - The pass template key
curl -X GET 'https://api.passninja.com/v1/passes/<YOUR_PASS_TYPE>/<SERIAL_NUMBER>' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>'
You will get a response with the pass object including all field values. Example response:
{
"serialNumber": "<SERIAL_NUMBER>",
"id": "<SERIAL_NUMBER>",
"pass": {
"discount": "50%",
"member-name": "John",
"loyalty-points": "1234"
},
"urls": {
"landing": "https://i.installpass.es/p/<SERIAL_NUMBER>"
},
"passType": "<YOUR_PASS_TYPE>"
}
Decrypt a pass
Allows you to decrypt a pass payload using it's pass type and encrypted payload.
Below is a list of required params for decrypting a pass:
-
passType* stringThis is the pass type key, it is present in the getting started tab for a given pass template. It looks like this:
<YOUR_PASS_TYPE> -
payload* stringPayload is a hex encoded APDUs with no spaces. It looks like this (abbreviated for presentation):
55166a97002...1ea070f0d4fe88887
curl -X POST 'https://api.passninja.com/v1/passes/<YOUR_PASS_TYPE>/decrypt' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>' \
-H 'Content-Type: application/json' \
-d '{
"payload": "55166a9700250a8c51382dd16822b0c763136090b91099c16385f2961b7d9392d31b386cae133dca1b2faf10e93a1f8f26343ef56c4b35d5bf6cb8cd9ff45177e1ea070f0d4fe88887"
}'
Update a pass
Allows you to update a pass using it's pass type, pass id and new information. This update will occur as soon as possible, but may not be instant - it will depend on the service of the users device.
Below is a list of required params for updating a pass:
-
passType* stringThis is the pass type key, it is present in the getting started tab for a given pass template. It looks like this:
<YOUR_PASS_TYPE> -
passId* stringPassId also known as a serial number. Takes on a namespaced format which looks like
<SERIAL_NUMBER> -
pass* objectThe keys for this object are defined in the pass ninja console, and can be found in the getting started tab for a given pass template.
curl -X PUT 'https://api.passninja.com/v1/passes/<YOUR_PASS_TYPE>/<SERIAL_NUMBER>' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>' \
-H 'Content-Type: application/json' \
-d '{
"pass": {
"discount": "100%",
"member-name": "Ted"
}
}'
You will get a response with the updated pass object including all field values. Example response:
{
"serialNumber": "<SERIAL_NUMBER>",
"id": "<SERIAL_NUMBER>",
"pass": {
"discount": "100%",
"member-name": "Ted",
"loyalty-points": "1234"
},
"urls": {
"landing": "https://i.installpass.es/p/<SERIAL_NUMBER>"
},
"passType": "<YOUR_PASS_TYPE>"
}
Delete a pass
An irreversible action to destroy a pass using it's pass type and pass id, also known as it's serial number. Will not remove the pass from users device, but will void the pass at the earliest possible moment and prevent additional billing events immediately.
Below is a list of required params for deleting a pass:
-
passType* stringThis is the pass type key, it is present in the getting started tab for a given pass template. It looks like this:
<YOUR_PASS_TYPE> -
passId* stringPassId also known as a serial number. Takes on a namespaced format which looks like
<SERIAL_NUMBER>
curl -X DELETE 'https://api.passninja.com/v1/passes/<YOUR_PASS_TYPE>/<SERIAL_NUMBER>' \
-H 'X-API-KEY: <YOUR_API_KEY>' \
-H 'X-ACCOUNT-ID: <YOUR_ACCOUNT_ID>'
You will get a response with the deleted pass serial number. Example response:
"<SERIAL_NUMBER>"
Webhook payload
If you have webhooks enabled, you we will send you a JSON payload like the one below whenever the user completes any of the following actions:
- Installs a pass
- Uninstalls a pass
We will automatically retry delivery until your server responds with an HTTP status code in the 200 range for up to 24 hours. At that point, no further attempts will be conducted.
{
"passType": "<YOUR_PASS_TYPE>",
"passId": "<SERIAL_NUMBER>",
"event": "install",
"eventDate": "2024-04-23T18:25:43.511Z",
"attempt": 1
}
Errors: Standard codes
We return a standard set of error codes, in addition to standard HTTP status codes. You can find the full list below:
| Error code | HTTP Status | Meaning |
|---|---|---|
| UA1 | 401 | Unauthorized request - you are missing a required header. Please review the Authentication section. |
| MP1 | 402 | Missing credits - you are missing credits to use the API. |
| UA2 | 403 | Forbidden - you are attempting to access someone elses passes - please stop. |
| RL1 | 429 | Rate limit exceeded - you are sending too many requests, perhaps you are being throttled by adding recipients to pass creation. You may want to upgrade to an enterprise plan. |
| MR1 | 404 | Pass template does not exist - you are attempting to use a pass template that does not exist. |
| MR2 | 404 | Pass does not exist - you are attempting to access a pass that does not exist - it may have been destroyed. |
| MI1 | 400 | Invalid pass body - The keys you are using for this pass template or pass do not fit the schema you defined in the PassNinja developer console. |
| IP1 | 400 | Incompatible platform - The payload you are trying to decrypt is not decryptable because the pass is not for Apple. |
| GE77 | 500 | Generic Error - Sometimes things go wrong, we're sorry and we will investigate. |
Terminal: Simple readers
If you're using one of our developer terminals, then you may be wondering what the output stream from the terminal is. Our readers emulate a keyboard device and stream the NFC data to stdin, encoded in ASCII format.