Turn a Loyalty Card into a digital stamp card and update each member's stamp progress through the PassKit API.
This guide is written for beginners, but you will need basic experience sending API requests and an existing PassKit Loyalty Card program.
What this guide covers
Creating the stamp card image
Adding the image to a Loyalty Card template
Setting a member's current stamps
Updating stamps after a visit or purchase
Testing the finished card in Apple Wallet and Google Wallet
Before you start
You will need:
A PassKit membership card program
The ID of the tier you want to turn into a stamp card
The ID of that tier's current pass template/design
The existing icon and logo image IDs used by the template
A way to send authenticated requests to the PassKit API
A test member and a phone with Apple Wallet or Google Wallet
Important: Use an Apple store-card (Loyalty) style design for a stamp card. Generic, boarding-pass and event-ticket designs do not support the stamp image in the required way.
Terminology
Program
Your membership card project in PassKit.
Tier
A group of members that shares the same card design. If your program has only one design, you will normally use its base tier.
Template/design
The shared appearance and settings for every membership card in a tier.
Stamp image
The image generated by PassKit that contains the stamp layout, colours, filled stamps and empty stamp positions.
Member
The individual person who receives the membership card. Each member can have a different stamp status.
Bitmask
A number that tells PassKit exactly which stamp positions are filled. You do not need advanced programming knowledge to use it; examples and a simple calculation method are included below.
Step 1: Create the stamp image
Send a POST request to /images using the JSON below.
This example creates a ten-position coffee stamp card with a pink background. Filled positions are white and empty positions appear faintly.
{
"name": "10 stamp membership card",
"imageData": {
"stampConfig": {
"padding": 40,
"totalStamps": 10,
"stampImage": "coffee",
"unstampImage": "coffee",
"backgroundColor": "#DB84D3",
"backgroundOpacity": 1,
"stampColor": "#FFFFFF",
"stampOpacity": 1,
"unstampColor": "#FFFFFF",
"unstampOpacity": 0.2,
"placeholders": true,
"placeholderColor": "#DB84D3",
"placeholderOpacity": 1,
"placeholderBorderColor": "#FFFFFF",
"placeholderBorderOpacity": 1
}
}
}
PassKit returns a stamp image ID. Copy and save this value:
{
"stampImage": "STAMP_IMAGE_ID"
}
You will use STAMP_IMAGE_ID in the next step.
Common stamp image options
totalStamps | Number of stamp positions. The maximum is 50. |
stampImage | Visual for a filled position. Built-in choices include coffee, star, tick and stamp-tick. |
unstampImage | Optional visual for an empty position. |
backgroundColor | Background colour as a hex value, for example #DB84D3. |
stampColor | Colour of filled built-in stamp images. |
unstampColor | Colour of empty built-in stamp images. |
placeholders | Set to true to show a slot behind each stamp position. |
padding | Space around the layout. Use a number from 0 to 50. |
Opacity values run from 0 (invisible) to 1 (fully visible).
Step 3: Add the stamp image to the membership template
Update the template/design for the tier and add the new ID as imageIds.stampImage.
Include the icon and logo IDs already used by your template so they are preserved:
Snippet
{
"imageIds": {
"icon": "ICON_ID",
"logo": "LOGO_ID",
"stampImage": "STAMP_IMAGE_ID"
}
}
Note: When updating the template record, the full template JSON needs to be sent.
Step 4: Enrol a member with stamps
When you enrol a member, add stamp.status inside metaData.
This will require using our API, CSV Import function, or no code solutions like Make and Zapier.
Example
{
"programId": "PROGRAM_ID",
"tierId": "TIER_ID",
"externalId": "member-001",
"person": {
"displayName": "Example Member",
"emailAddress": "example.member@example.com"
},
"metaData": {
"stamp.status": ""
}
}
Understanding stamp.status
stamp.status lets you choose exactly which stamp positions are filled, including positions that aren’t next to each other.
Common values for a ten-stamp card
stamp.status | Filled Positions |
0 | None |
1 | Postion 1 |
3 | Positions 1 and 2 |
31 | Positions 1 to 5 |
341 | Positions 1, 3, 5, 7 and 9 |
1023 | All 10 positions |
Calculate a custom combination
Each position has its own value:
Position | Value | Position | Value |
1 | 1 | 6 | 32 |
2 | 2 | 7 | 64 |
3 | 4 | 8 | 128 |
4 | 8 | 9 | 256 |
5 | 16 | 10 | 512 |
Add together the values for the positions you want to fill.
For example, to fill positions 1, 3 and 5:
Position 1 = 1
Position 3 = 4
Position 5 = 16
1 + 4 + 16 = 21
Use this metadata:
{
"metaData": {
"stamp.status": "21"
}
}
For consecutive stamps from position 1, you can use this shortcut:
2 raised to the number of stamps, minus 1
For five stamps: 2⁵ - 1 = 31.
Explanation
Multiply 2 by itself once for each stamp, then subtract 1.
For five stamps: 2 × 2 × 2 × 2 × 2 − 1 = 31.
Step 5: Update an existing member's stamps
Identify the member by their PassKit member ID, or by programId and externalId, then send the updated metadata.
This example changes the member to five consecutive stamps:
{
"Id": "PROGRAM_ID",
"metaData": {
"stamp.status": "31"
}
}
Always send the full new stamp status. For example, changing 31 to 63 displays positions 1 to 6. Do not send only the value of the newly added position unless your own application first combines it with the member's current value.
Step 6: Test the stamp card
1. Create or use a test member in the stamp card tier.
2. Open the member's pass URL.
3. Add the pass to Apple Wallet or Google Wallet.
4. Confirm the stamp layout, colours and empty positions look correct.
5. Update the member's stamp.status.
6. Open the pass again and confirm the expected positions are filled.
Test both Apple Wallet and Google Wallet before using the setup with live members
Optional stamp configuration fields
Field | Description |
backgroundImage | Background image ID, URL or base64 image. You can also use this when the supplied strip image should become the background. |
backgroundOpacity | Background opacity from 0 to 1. |
stampOpacity | Filled-stamp opacity from 0 to 1. |
unstampOpacity | Empty-stamp opacity from 0 to 1. |
placeholderColor | Placeholder fill colour. |
placeholderOpacity | Placeholder fill opacity from 0 to 1. |
placeholderBorderColor | Placeholder border colour. |
placeholderBorderOpacity | Placeholder border opacity from 0 to 1. |
rewardPlaceholders | Set to true to give selected positions a reward style. |
rewardPositions | Bitmask identifying the reward positions. For example, 528 marks positions 5 and 10. |
rewardBorderColor | Reward placeholder border colour. |
rewardBorderOpacity | Reward placeholder border opacity from 0 to 1. |
rewardBackgroundColor | Reward placeholder fill colour. |
rewardBackgroundOpacity | Reward placeholder fill opacity from 0 to 1. |
Troubleshooting
The stamp image does not appear in Apple Wallet
Confirm the membership card uses a store-card style Apple design.
Confirm the template contains imageIds.stampImage.
Confirm you used the stamp image ID returned by POST /images.
Remove an unnecessary standard strip image while testing.
The stamp image does not appear as the Google Wallet hero image
Check whether a hero or thumbnail image has been set for the individual member. A member-level image can override the stamp card image.
The wrong stamps are filled
Recalculate the bitmask by adding the values for the required positions. Remember that position 1 is 1, position 2 is 2, position 3 is 4, and each following value doubles.
A new stamp replaces the existing stamps
Send the complete bitmask for all positions that should remain filled. Do not send only the value of the newest stamp.
Changes affect more members than expected
The stamp image belongs to the tier template, so image and layout changes apply to every member in that tier. Test template changes in a test tier before applying them to a live tier.
Summary
To create a membership stamp card:
1. Use a store-card style Apple design.
2. Create the stamp image with POST /images.
3. Add the returned ID to the tier template as imageIds.stampImage.
4. Set each member's filled positions using metaData["stamp.status"].
5. Test the result in both Apple Wallet and Google Wallet.
