← Back to list

Generating Apple Wallet Pass using jPassKit 0.4.0 in MuleSoft

A full walkthrough — from pass.json to a signed .pkpass returned by a MuleSoft API, including what Apple lets you customise and what it…

Chetna Rathod · 2026-05-20 18:44 · 0 claps · 9.5 min read paywalled
#mulesoft-integration #mulesoft #apple-wallet #api-integration #java
Open on Medium ↗

Generating Apple Wallet Pass using jPassKit 0.4.0 in MuleSoft

A full walkthrough — from pass.json to a signed .pkpass returned by a MuleSoft API, including what Apple lets you customise and what it doesn't.

In this blog, we will cover how to generate an Apple Wallet Pass (.pkpass file) using the jPassKit 0.4.0 library in Java and invoke it inside a MuleSoft flow.

Apple Wallet passes are everywhere — loyalty cards, boarding passes, event tickets, coupons, gym memberships. If you have ever wondered how companies push digital passes straight to a user’s iPhone Wallet, this blog is for you.

Official Apple Documentation — bookmark these before you start, they are the single source of truth:

Let’s start by understanding the key players involved.

What is an Apple Wallet Pass?

Apple Wallet (formerly Passbook) lets users store passes — boarding passes, loyalty cards, coupons, event tickets — on their iPhone or Apple Watch. A pass is distributed as a .pkpass file, which is really just a ZIP archive containing:

  • pass.json — pass data and structure
  • Image assets — icon, logo, strip, thumbnail, etc.
  • manifest.json — SHA-1 hashes of every file
  • signature — PKCS#7 detached signature, produced with your Apple certificate

What is jPassKit?

jPassKit is an open-source Java library that takes most of the pain out of generating Apple Wallet passes. It builds pass.json for you, creates the manifest, and signs everything with your certificates.

We will be using version 0.4.0.

<dependency>
    <groupId>de.brendamour</groupId>
    <artifactId>jpasskit</artifactId>
    <version>0.4.0</version>
</dependency>

End-to-End Flow

Before we look at code, here is the full picture — what happens between a client hitting our MuleSoft endpoint and the pass landing in the user’s Wallet.

Prerequisites

Before we dive in, make sure you have:

  1. Apple Developer Account (paid) — required to generate the certificates.
  2. Pass Type ID and a pass-signing certificate (.p12) downloaded from the Apple Developer portal.
  3. Apple WWDR certificate (G4 or G5) — the Apple Worldwide Developer Relations intermediate certificate.
  4. Java 8+ and Maven in your project.
  5. A MuleSoft Anypoint project, if you want to expose pass generation as an API.

All set? Let’s go.

Understanding the Pass Structure

A .pkpass file is a ZIP archive with a specific structure:

MyEventPass.pkpass
├── pass.json          ← The core data file
├── manifest.json      ← SHA-1 hashes of all files
├── signature          ← PKCS#7 detached signature
├── icon.png           ← 1x icon
├── icon@2x.png        ← 2x icon
├── logo.png           ← Pass logo (top left)
├── logo@2x.png
├── strip.png          ← Background strip image
└── strip@2x.png

The pass.json is the brain of everything. It defines the pass type, the fields shown on the front, the colours, the barcode, relevance triggers — everything. jPassKit gives you a clean Java API to build this programmatically.

Visually, here is how each region of an event ticket maps to the data you supply:

Building the Event Pass — Step by Step

Let’s build a complete event ticket pass using jPassKit 0.4.0.

Step 1 — Create the Pass Object

First, build the pass.json structure using jPassKit's PKPass class.

import de.brendamour.jpasskit.*;
import de.brendamour.jpasskit.enums.*;
import de.brendamour.jpasskit.passes.*;
import java.util.*;
public PKPass createEventPass() {
    // Primary field — shown prominently on the pass
    PKField eventName = PKField.builder()
        .key("event")
        .label("EVENT")
        .value("TechConf 2026")
        .build();
    PKField dateField = PKField.builder()
        .key("date")
        .label("DATE")
        .value("May 25, 2026")
        .build();
    PKField locationField = PKField.builder()
        .key("location")
        .label("VENUE")
        .value("Mumbai, India")
        .build();
    // Event ticket structure
    PKEventTicket eventTicket = PKEventTicket.builder()
        .primaryField(eventName)
        .secondaryField(dateField)
        .auxiliaryField(locationField)
        .build();
    // QR barcode
    PKBarcode barcode = PKBarcode.builder()
        .format(PKBarcodeFormat.PKBarcodeFormatQR)
        .message("TICKET-2026-00123")
        .messageEncoding("iso-8859-1")
        .build();
    // The main pass object
    PKPass pass = PKPass.builder()
        .passTypeIdentifier("pass.com.yourcompany.eventpass")
        .serialNumber("TICKET-2026-00123")
        .teamIdentifier("YOUR_TEAM_ID")
        .organizationName("TechConf India")
        .description("TechConf 2026 Event Ticket")
        .foregroundColor("rgb(255, 255, 255)")
        .backgroundColor("rgb(63, 81, 181)")
        .labelColor("rgb(200, 200, 255)")
        .eventTicket(eventTicket)
        .barcode(barcode)
        .build();
    return pass;
}

PKEventTicket maps to Apple's eventTicket pass style. You can swap it for PKBoardingPass, PKCoupon, PKGenericPass, or PKStoreCard depending on your use case — but be aware that each pass style has its own field limits and layout rules (more on that in the limitations section).

Step 2 — Sign and Package the Pass

This is the most important step. jPassKit handles signing internally using your .p12 certificate and the Apple WWDR certificate.

import de.brendamour.jpasskit.signing.*;
import java.io.*;
import java.nio.file.*;
public byte[] signAndPackagePass(PKPass pass) throws Exception {
    // Load signing configuration
    PKSigningInformationUtil signingUtil = new PKSigningInformationUtil();
    PKSigningInformation signingInfo = signingUtil
        .loadSigningInformationFromPKCS12AndIntermediateCertificate(
            "path/to/Certificates.p12",    // Your .p12 file
            "your_p12_password",            // Password for .p12
            "path/to/AppleWWDRCA.cer"       // Apple WWDR Certificate
        );
    // Point to the folder containing your images
    IPKPassTemplate passTemplate = new PKPassTemplateFolder("path/to/pass-images/");
    // Create the signer
    PKFileBasedSigningUtil pkSigningUtil = new PKFileBasedSigningUtil();
    // Generate the signed .pkpass as bytes
    byte[] pkpassData = pkSigningUtil.createSignedAndZippedPkPassArchive(
        pass, passTemplate, signingInfo
    );
    return pkpassData;
}

createSignedAndZippedPkPassArchive() does the heavy lifting — creates manifest.json, signs with your certificate, and packages everything into the .pkpass ZIP.

Step 3 — Integrating with MuleSoft

Now wire it into a MuleSoft flow. Expose an HTTP endpoint that accepts a request, calls the Java class, and streams the .pkpass binary back.

<flow name="generate-apple-pass-flow">
    <!-- HTTP Listener -->
    <http:listener config-ref="HTTP_Listener_config"
                   path="/generate-pass"
                   method="POST"
                   doc:name="HTTP Listener"/>
    <!-- Invoke the Java pass generator -->
    <java:invoke-static
        class="com.yourcompany.PassGeneratorService"
        method="generateEventPass(String, String, String)"
        doc:name="Generate Apple Wallet Pass">
        <java:args>#[{
            eventName: payload.eventName,
            date: payload.date,
            venue: payload.venue
        }]</java:args>
    </java:invoke-static>
    <!-- Stream the pkpass bytes back -->
    <set-variable variableName="pkpassBytes"
                  value="#[payload]"
                  doc:name="Store Pass Bytes"/>
    <set-payload value="#[vars.pkpassBytes]"
                 doc:name="Set Payload"/>
    <http:response-builder statusCode="200">
        <http:headers>
            <http:header headerName="Content-Type"
                         value="application/vnd.apple.pkpass"/>
            <http:header headerName="Content-Disposition"
                         value="attachment; filename=event-pass.pkpass"/>
        </http:headers>
    </http:response-builder>
</flow>

Anypoint Studio Visual Flow: generate-apple-pass-flow

The two headers above are non-negotiable. application/vnd.apple.pkpass is the MIME type iOS uses to recognise the file as a Wallet pass — get it wrong and Safari/Mail will just download it as a generic zip.

Apple Wallet — What You Can and Cannot Customise

This is the part most developers learn the hard way. You do not have full design control over a Wallet pass. Apple’s runtime decides a lot of things for you, and that is by design — passes have to look consistent, accessible, and scannable across iPhone, Apple Watch, lock screen, and Mail previews.

Here’s the cheat sheet I wish I had on day one:

Hard limitations you need to plan around

Pulled from the Apple Human Interface Guidelines — Designing passes and the Wallet Developer Guide:

1. You cannot change the font family. Apple uses the system font on every pass, on every device. There is no font key in pass.json and no way to ship a custom typeface inside a .pkpass. Apple's HIG explicitly says: "avoid using custom fonts that might make text hard to read."

2. You cannot set font size or weight. Wallet sizes text automatically. The size depends on the pass style (event tickets keep text larger, coupons and store cards compress it more), the length of the value, how many fields share a row, and the user’s accessibility text-size setting. A short value renders larger than a long one in the same slot — you can’t override this.

3. Field positions are fixed by pass style. You pick a style — eventTicket, boardingPass, coupon, storeCard, or generic — and that style decides where the logo, primary field, secondary fields, auxiliary fields, strip image, and barcode live. You can't drag things around.

4. Field counts per style are capped. Each style has a documented maximum:

Pass style Primary Secondary + auxiliary (front) Back fields eventTicket 1 up to 4 combined on the front unlimited boardingPass up to 2 up to 5 auxiliary unlimited coupon 1 up to 4 in one row unlimited storeCard 1 up to 4 in one row (+ optional extra auxiliary row) unlimited generic 1 up to 4 in one row unlimited

If you stuff in a fifth secondary field, Wallet will silently drop it.

5. Long values get truncated with no fixed character count. There is no “max length” you can rely on. Apple dynamically truncates with an ellipsis () based on the value, the device width, the user's font-size setting, and what other fields share the row. Treat field values as short labels, never paragraphs. Put long text on the back of the pass — there's no length cap there, and Wallet shrinks the font as content grows.

6. Embedded text inside images is discouraged. From the HIG: “Don’t embed text in images — it’s not accessible and not all images are displayed on all devices.” VoiceOver can read field text; it cannot read pixels.

7. Image sizes are dictated, not suggested. You ship @1x, @2x, and @3x variants. Sizes per asset (the canonical reference is Apple's HIG — Pass image dimensions):

Asset @1x @2x @3x icon 29 × 29 58 × 58 87 × 87 logo up to 160 × 50 320 × 100 480 × 150 strip (event) 375 × 98 750 × 196 1125 × 294 strip (coupon/storeCard) 375 × 144 750 × 288 1125 × 432 thumbnail 90 × 90 180 × 180 270 × 270 background 180 × 220 360 × 440 540 × 660

The background image is always cropped and blurred by the system. You can’t disable that blur — it’s part of the look.

8. Color customisation is RGB only and limited to three keys. You get backgroundColor, foregroundColor, and labelColor — all in rgb(r, g, b) format. No per-field colors, no gradients, no opacity. Hyperlinks on the back of the pass always render in the system blue.

9. Barcode formats are fixed. Only PKBarcodeFormatQR, PKBarcodeFormatPDF417, PKBarcodeFormatAztec, and PKBarcodeFormatCode128. No Code 39, no Data Matrix, no custom symbology.

The mental model

You build the content. Apple builds the chrome.

Anything you’d want to tweak for “branding” beyond color and a logo image — typography, spacing, alignment of the pass title, button shapes — is off the table. Plan your design around this, not against it.

Testing the API with Postman

Time to actually call our MuleSoft endpoint and see a .pkpass come back.

cURL

curl --location --request POST 'https://mulesoft.dev.example.com/api/generate-pass' \
  --header 'Content-Type: application/json' \
  --header 'client_id: your_anypoint_client_id' \
  --header 'client_secret: your_anypoint_client_secret' \
  --data '{
    "eventName": "TechConf 2026",
    "date": "May 25, 2026",
    "venue": "Mumbai, India",
    "serialNumber": "TICKET-2026-00123",
    "organizationName": "TechConf India"
  }' \
  --output event-pass.pkpass

The --output event-pass.pkpass is important. The response body is a binary ZIP, so if you forget it the bytes will get mangled in your terminal.

Expected response

HTTP/1.1 200 OK
Content-Type: application/vnd.apple.pkpass
Content-Disposition: attachment; filename=event-pass.pkpass
Content-Length: 12683
Date: Wed, 20 May 2026 09:17:42 GMT
<binary .pkpass payload>

If the cert chain is wrong, the most common failure modes are:

HTTP / log Likely cause 500 + PKSigningException: keystore password Wrong .p12 password 500 + unable to find valid certification path WWDR .cer missing or wrong version (use G4 or G5) 400 from MuleSoft Payload validation failed before the Java invoke 200 but iPhone says "Pass cannot be installed" teamIdentifier / passTypeIdentifier doesn't match the .p12

Postman snapshot

Send the request in Postman, hit Save Response → Save to a file as event-pass.pkpass, then AirDrop it to your iPhone (or email yourself).

The Final Output — Pass on iPhone

When the user opens event-pass.pkpass on iPhone (from Mail, Messages, AirDrop, or a browser download), iOS shows the Add Pass sheet. Tapping Add drops it into Wallet.

A few things worth pointing out about the rendered pass:

  • The organizationName you set in code shows next to the logo at the top.
  • EVENT, DATE, VENUE are the labels — Apple renders them in labelColor (the lighter blue here) and uppercases them.
  • The values use foregroundColor.
  • The QR code at the bottom is barcode.message. Wallet also renders the smaller version on Apple Watch automatically.
  • Notice the font and size — that’s the system font, sized by Wallet, not by us. If “TechConf 2026” were a longer string like “TechConf India 2026 — Mumbai Edition”, Wallet would shrink it or truncate it with an ellipsis.

Common pitfalls (saving you a debugging weekend)

  • **teamIdentifier and passTypeIdentifier must match the certificate.** If they don't, the pass signs fine but iPhone refuses to install it with a generic error.
  • PNG only. No JPEGs, no WebP, no SVG. And icon.png is mandatory — without it, the pass won't install even though it'll look fine in your folder.
  • Ship @2x at minimum. @1x alone looks blurry on any iPhone from the last decade.
  • Don’t reuse serialNumber if you also use webServiceURL for updates — Wallet uses the combination of pass type ID + serial number as a unique key.
  • WWDR certificate expires. Apple rotates it (currently G4/G5). When your existing one expires, every pass you sign with it stops being installable. Set a calendar reminder.
  • Sign on the server, never on the client. Your .p12 is your identity — keep it in MuleSoft's secure properties, never in a mobile app or a public repo.

Wrapping up

You now have a complete MuleSoft API that takes a JSON payload, builds an Apple Wallet pass with jPassKit 0.4.0, signs it with your Apple certificates, and returns a ready-to-install .pkpass file. You also know exactly which design controls you have — and which ones Apple keeps for itself.

If this saved you a few hours of certificate-debugging pain, give it a clap and a follow. Got questions or running into a signing error I didn’t cover? Drop a comment — happy to dig in.

Next in this series: push-updating an issued pass via webServiceURL so you can change the seat number, gate, or balance after the user has already added the pass to their Wallet.

Conclusion: By folllowing all these steps you will be able to generate apple wallet pass using mulesoft successfully. Happy Learning!!

Tags: MuleSoft, Apple Wallet, jPassKit, PassKit, Java, Integration, iOS, Mobile Wallet, API Development

mulesoft #AppleWallet #jpasskit #passkit #java #integration #ios #mobileWallet #apidevelopment


메타데이터
post_id
66875c622f8a
slug
generating-apple-wallet-pass-using-jpasskit-0-4-0-in-mulesoft-66875c622f8a
url
https://medium.com/@rchetna594/generating-apple-wallet-pass-using-jpasskit-0-4-0-in-mulesoft-66875c622f8a
canonical_url
https://medium.com/@rchetna594/generating-apple-wallet-pass-using-jpasskit-0-4-0-in-mulesoft-66875c622f8a
author_url
https://medium.com/@rchetna594
status
ok
fetched_at
2026-06-09 15:37:30