@molecule/api-wallet-pass
Feature · wallet-pass · API (Node) · v1.0.2 · Apache-2.0
Apple Wallet (.pkpass) + Google Wallet pass-object generation. Signs Apple manifests with CMS detached signatures and Google pass JWTs with RS256. Framework-neutral HTTP handlers for ticket / coupon delivery.
npm install @molecule/api-wallet-passHow it works
@molecule/api-wallet-pass is a ready-made wallet-pass feature for the API (Node) side. It composes the core interfaces it needs, so it works with whichever providers your app has bonded.
import { createApplePass, createGoogleWalletJwt } from '@molecule/api-wallet-pass'
// Apple
const pkpass = await createApplePass(passJsonPayload, signingCerts, assets)
// Google — event ticket (default)
const jwt = createGoogleWalletJwt(passClass, passObject, serviceAccount)
const saveUrl = `https://pay.google.com/gp/v/save/${jwt}`
// Google — coupon (offer pass type)
const couponJwt = createGoogleWalletJwt(passClass, passObject, serviceAccount, undefined, 'coupon')Reference
Apple Wallet (.pkpass) and Google Wallet pass-object generation for server-side ticket / coupon delivery.
Two independent sub-APIs:
createApplePass— produces a signed.pkpasszip (CMS detached signature overmanifest.json, using the Apple developer-portal "Pass Type ID" cert + WWDR intermediate). Output is aBufferready to send withContent-Type: application/vnd.apple.pkpass.createGoogleWalletJwt— produces an RS256-signed JWT containing the pass class + pass object payloads for the selectedGoogleWalletPassType(event ticket, offer/coupon, loyalty, gift card, flight, transit, or generic). Embed the JWT intohttps://pay.google.com/gp/v/save/<jwt>for the "save to wallet" flow.
Two HTTP handlers — createApplePassHandler and
createGoogleWalletPassHandler — wrap the generators with the same
minimal request/response contract used elsewhere in @molecule/api-*,
keeping the package framework-neutral.
The package never displays text on its own and has no companion locale bond: pass field labels are caller-supplied and already localized.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { createApplePass, createGoogleWalletJwt } from '@molecule/api-wallet-pass'
// Apple
const pkpass = await createApplePass(passJsonPayload, signingCerts, assets)
// Google — event ticket (default)
const jwt = createGoogleWalletJwt(passClass, passObject, serviceAccount)
const saveUrl = `https://pay.google.com/gp/v/save/${jwt}`
// Google — coupon (offer pass type)
const couponJwt = createGoogleWalletJwt(passClass, passObject, serviceAccount, undefined, 'coupon')
Type
feature
Installation
npm install @molecule/api-wallet-pass node-forge
npm install -D @types/node-forge
API
Interfaces
WalletPassRequest
Minimal request shape consumed by the wallet-pass handlers.
interface WalletPassRequest {
/** Path params; both handlers expect `passId`. */
params: { passId: string }
}
WalletPassResponse
Minimal response shape consumed by the wallet-pass handlers.
interface WalletPassResponse {
/** Set a single response header. */
setHeader: (name: string, value: string) => void
/** Set the HTTP status code. */
setStatus: (status: number) => void
/** Write a binary buffer body and end the response. */
sendBuffer: (buffer: Buffer) => void
/** Write a JSON body and end the response. */
sendJson: (body: unknown) => void
/** Issue a redirect (302). */
redirect: (url: string) => void
}
CreateApplePassHandlerOptions
Options for createApplePassHandler.
interface CreateApplePassHandlerOptions {
/** Loader that turns `passId` into the pass payload + signing material. */
resolve: ApplePassResolver
/** Optional file-name template for the `Content-Disposition` header. */
fileName?: (passId: string) => string
}
CreateGoogleWalletPassHandlerOptions
Options for createGoogleWalletPassHandler.
interface CreateGoogleWalletPassHandlerOptions {
/** Loader that turns `passId` into pass class + object + signing creds. */
resolve: GoogleWalletPassResolver
/** Override the Google Wallet save-link prefix (used by tests). */
saveUrlPrefix?: string
}
ApplePassBarcode
Apple Wallet barcode entry, used for both the legacy barcode field and
the modern barcodes[] array on pass.json.
interface ApplePassBarcode {
/** Barcode visual format. */
format: ApplePassBarcodeFormat
/** Encoded payload (URL, ticket id, JWT, etc.). */
message: string
/** Encoding for `message`. Almost always `'iso-8859-1'`. */
messageEncoding: string
/** Optional human-readable text shown beneath the barcode. */
altText?: string
}
ApplePassField
A single primary/secondary/auxiliary/back/header field on an Apple Wallet
pass. Apple's schema lets each field carry an arbitrary key, a localized
label, and a value (string or number). Additional formatting fields
(currencyCode, dateStyle, etc.) are passed through verbatim.
interface ApplePassField {
/** Stable field id. Must be unique within its parent style group. */
key: string
/** Localized label shown above the value. */
label?: string
/** Field value (string, number, ISO-8601 date, etc.). */
value: string | number
/** Localized text alignment. Apple-defined enum. */
textAlignment?:
| 'PKTextAlignmentLeft'
| 'PKTextAlignmentCenter'
| 'PKTextAlignmentRight'
| 'PKTextAlignmentNatural'
/** ISO-4217 currency code; turns the value into a localized currency string. */
currencyCode?: string
/** Date style for date-typed values. */
dateStyle?:
| 'PKDateStyleNone'
| 'PKDateStyleShort'
| 'PKDateStyleMedium'
| 'PKDateStyleLong'
| 'PKDateStyleFull'
/** Time style for date-typed values. */
timeStyle?:
| 'PKDateStyleNone'
| 'PKDateStyleShort'
| 'PKDateStyleMedium'
| 'PKDateStyleLong'
| 'PKDateStyleFull'
/** Number style for numeric values. */
numberStyle?:
| 'PKNumberStyleDecimal'
| 'PKNumberStylePercent'
| 'PKNumberStyleScientific'
| 'PKNumberStyleSpellOut'
/** Optional change message template (`'%@'` is replaced with the new value). */
changeMessage?: string
}
ApplePassStyleFields
The structured field groups that live under one of the pass-style keys
(eventTicket, boardingPass, etc.) in pass.json.
interface ApplePassStyleFields {
headerFields?: ApplePassField[]
primaryFields?: ApplePassField[]
secondaryFields?: ApplePassField[]
auxiliaryFields?: ApplePassField[]
backFields?: ApplePassField[]
}
ApplePassData
The minimum set of fields Apple's signing server validates. Other fields (relevantDate, locations, beacons, NFC, etc.) are passed through verbatim via the index signature so callers can populate any of Apple's documented keys without us having to re-export the entire schema.
interface ApplePassData {
/** Schema version. Always `1` for the current PassKit format. */
formatVersion: 1
/** Reverse-DNS pass-type id from the Apple developer portal. */
passTypeIdentifier: string
/** Apple developer team id (10 chars). */
teamIdentifier: string
/** Per-pass unique serial number. */
serialNumber: string
/** Customer-facing org name shown in the lock screen. */
organizationName: string
/** Localized short description for accessibility. */
description: string
/** Pass background color in `'rgb(r, g, b)'` form. */
backgroundColor?: string
/** Foreground (primary text) color in `'rgb(r, g, b)'` form. */
foregroundColor?: string
/** Label text color in `'rgb(r, g, b)'` form. */
labelColor?: string
/** Logo text shown next to the logo image. */
logoText?: string
/** Modern multi-barcode array. Prefer over the legacy `barcode` field. */
barcodes?: ApplePassBarcode[]
/** Legacy single-barcode field. Apple still requires it for old iOS versions. */
barcode?: ApplePassBarcode
/** Style-specific field group — exactly one of these keys must be present. */
eventTicket?: ApplePassStyleFields
boardingPass?: ApplePassStyleFields
coupon?: ApplePassStyleFields
generic?: ApplePassStyleFields
storeCard?: ApplePassStyleFields
/**
* Web-service URL Apple Wallet pings for pass updates. Required when
* `authenticationToken` is set.
*/
webServiceURL?: string
/** Token presented to the web service for pass updates. */
authenticationToken?: string
/** Pass-through for any remaining Apple-defined keys. */
[extra: string]: unknown
}
ApplePassCertificates
Certificate bundle required to sign an Apple .pkpass.
Apple's PassKit signing flow uses a CMS detached signature over the
manifest.json file. Three artefacts are required:
signerCertPem— the developer-portal "Pass Type ID" cert (PEM).signerKeyPem— the matching private key (PEM, optionally encrypted).wwdrCertPem— Apple's WWDR intermediate cert chained into the CMS.
Pass password if signerKeyPem is encrypted.
interface ApplePassCertificates {
/** PEM-encoded "Pass Type ID" leaf certificate. */
signerCertPem: string
/** PEM-encoded private key matching `signerCertPem`. */
signerKeyPem: string
/** PEM-encoded Apple WWDR intermediate certificate. */
wwdrCertPem: string
/** Decryption passphrase for `signerKeyPem`, if it is encrypted. */
password?: string
}
CreateApplePassOptions
Options accepted by createApplePass. The certificate bundle is
required; assets are optional but most apps need at least an icon.png.
interface CreateApplePassOptions {
/** Pass payload — becomes `pass.json` inside the zip. */
passData: ApplePassData
/** Apple signing material — see `ApplePassCertificates`. */
certificates: ApplePassCertificates
/** Optional binary assets keyed by file name. */
assets?: ApplePassAssets
}
GoogleWalletClass
Google Wallet "pass class" — the shared template all matching pass objects inherit from. Apps typically create one class per event / loyalty-program and many objects underneath it.
The shape mirrors Google's REST schema; only id is required at this
layer. All other Google fields (eventName, venue, dateTime, redemptionIssuers,
etc.) are accepted via the index signature, so the same interface serves
every GoogleWalletPassType (event ticket, offer/coupon, loyalty, …).
interface GoogleWalletClass {
/** Globally unique class id, formatted `'<issuerId>.<suffix>'`. */
id: string
/** Pass-through for Google-defined keys (eventName, venue, etc.). */
[key: string]: unknown
}
GoogleWalletObject
Google Wallet "pass object" — the per-user instance of a class.
The shape mirrors Google's REST schema; id and classId are required.
All other Google fields (state, ticketHolderName, barcode, etc.) are
accepted via the index signature, so the same interface serves every
GoogleWalletPassType (event ticket, offer/coupon, loyalty, …).
interface GoogleWalletObject {
/** Globally unique object id, formatted `'<issuerId>.<suffix>'`. */
id: string
/** Class id this object inherits from. */
classId: string
/** Pass-through for Google-defined keys (state, barcode, etc.). */
[key: string]: unknown
}
GoogleWalletServiceAccount
Google service-account credentials used to sign Wallet JWTs.
Both fields come from the JSON key file Google issues for the
Wallet-issuer service account: client_email and private_key.
interface GoogleWalletServiceAccount {
/** Service-account email. */
clientEmail: string
/** PEM-encoded RSA private key (with `\n` newlines). */
privateKey: string
}
CreateGoogleWalletJwtOptions
Options accepted by createGoogleWalletJwt.
interface CreateGoogleWalletJwtOptions {
/** Pass class definition (template). */
passClass: GoogleWalletClass
/** Pass object definition (per-user instance). */
passObject: GoogleWalletObject
/** Google issuer service account. */
serviceAccount: GoogleWalletServiceAccount
/** JWT origins (audience domains). Defaults to `['https://wallet.google']`. */
origins?: string[]
/**
* Which Google Wallet pass type to emit. Defaults to `'eventTicket'`. Use
* `'offer'` (or `'coupon'`) for coupons — see `GoogleWalletPassType`.
*/
passType?: GoogleWalletPassType
}
ZipFileEntry
One file to embed in the zip.
interface ZipFileEntry {
/** Path inside the archive (no leading slash). */
name: string
/** Raw bytes to store. */
data: Buffer
}
Types
ApplePassResolver
Resolver that loads pass payload + signing material for a given passId. The handler stays decoupled from the storage layer (DataStore, files, cache, etc.) by accepting the resolver as a closure.
type ApplePassResolver = (passId: string) => Promise<
| {
passData: ApplePassData
certificates: ApplePassCertificates
assets?: ApplePassAssets
}
| undefined
>
GoogleWalletPassResolver
Resolver that loads Google Wallet pass class + object + signing service account for a given passId.
type GoogleWalletPassResolver = (passId: string) => Promise<
| {
passClass: GoogleWalletClass
passObject: GoogleWalletObject
serviceAccount: GoogleWalletServiceAccount
origins?: string[]
/**
* Which Google Wallet pass type to issue. Defaults to `'eventTicket'`.
* Return `'offer'`/`'coupon'` (etc.) to deliver a coupon.
*/
passType?: GoogleWalletPassType
}
| undefined
>
ApplePassBarcodeFormat
Apple Wallet barcode format. format controls how the redemption code is
rendered on the back of the pass.
'PKBarcodeFormatQR'— QR code (most common for event tickets).'PKBarcodeFormatPDF417'— PDF417 (US airline boarding passes).'PKBarcodeFormatAztec'— Aztec (international rail / boarding passes).'PKBarcodeFormatCode128'— Code-128 1D barcode.
type ApplePassBarcodeFormat =
'PKBarcodeFormatQR' | 'PKBarcodeFormatPDF417' | 'PKBarcodeFormatAztec' | 'PKBarcodeFormatCode128'
ApplePassStyle
Apple Wallet pass-style discriminator. Drives the visual layout of the pass on-device.
type ApplePassStyle = 'boardingPass' | 'coupon' | 'eventTicket' | 'generic' | 'storeCard'
ApplePassAssets
Optional asset attachments included alongside pass.json in the .pkpass
zip. Keys are the file names Apple expects (e.g. 'icon.png',
'icon@2x.png', 'logo.png', 'strip.png', 'thumbnail.png'). Each
value is the raw bytes of that asset.
type ApplePassAssets = Record<string, Buffer | Uint8Array>
GoogleWalletPassType
Google Wallet pass type. Selects which class/object payload keys the signed
JWT carries — Google routes each pass to a different on-device surface by
these keys, so the type MUST match the schema of passClass/passObject.
'eventTicket'— event tickets (eventTicketClasses/eventTicketObjects).'offer'/'coupon'— offers & coupons (offerClasses/offerObjects); Google Wallet has no separate "coupon" type — a coupon IS an offer, so the two spellings are aliases.'loyalty'— loyalty cards (loyaltyClasses/loyaltyObjects).'giftCard'— gift cards (giftCardClasses/giftCardObjects).'flight'— boarding passes (flightClasses/flightObjects).'transit'— transit passes (transitClasses/transitObjects).'generic'— generic passes (genericClasses/genericObjects).
type GoogleWalletPassType =
'eventTicket' | 'offer' | 'coupon' | 'loyalty' | 'giftCard' | 'flight' | 'transit' | 'generic'
Functions
createApplePass(passData, certificates, assets)
Generate a fully-signed Apple Wallet .pkpass archive.
function createApplePass(
passData: ApplePassData,
certificates: ApplePassCertificates,
assets?: ApplePassAssets,
): Promise<Buffer<ArrayBufferLike>>
passData— Thepass.jsonpayload (seeApplePassData).certificates— Signing material — seeApplePassCertificates.assets— Optional file-name → bytes map (icon.png, logo.png, ...).
Returns: A Buffer of the zipped, signed .pkpass ready to send with Content-Type: application/vnd.apple.pkpass.
createGoogleWalletJwt(passClass, passObject, serviceAccount, origins, passType)
Build and RS256-sign a Google Wallet JWT containing the pass class and
pass object. The returned string can be embedded directly into the
https://pay.google.com/gp/v/save/<jwt> redirect URL.
The passType selects which Google Wallet class/object keys the payload
carries, so the SAME function creates event tickets, offers/coupons, loyalty
cards, gift cards, boarding passes, transit passes, or generic passes —
routed via PASS_TYPE_PAYLOAD_KEYS. It is NOT hardcoded to event
tickets.
function createGoogleWalletJwt(
passClass: GoogleWalletClass,
passObject: GoogleWalletObject,
serviceAccount: GoogleWalletServiceAccount,
origins?: readonly string[],
passType?: GoogleWalletPassType,
): string
passClass— Pass class definition (template).passObject— Pass object definition (per-user instance).serviceAccount— Service-account email + RSA private key.origins— Optional origin domains; defaults to['https://wallet.google'].passType— Google Wallet pass type; defaults to'eventTicket'. Use'offer'(or'coupon') to issue a coupon. SeeGoogleWalletPassType.
Returns: A signed JWT string.
createApplePassHandler(options)
Build a (req, res) => Promise<void> handler for
GET /wallet/apple/:passId returning the signed .pkpass blob.
function createApplePassHandler(
options: CreateApplePassHandlerOptions,
): (req: WalletPassRequest, res: WalletPassResponse) => Promise<void>
options— Resolver + optional file-name builder.
Returns: Handler.
createGoogleWalletPassHandler(options)
Build a (req, res) => Promise<void> handler for
GET /wallet/google/:passId issuing a 302 redirect to the
https://pay.google.com/gp/v/save/<jwt> URL.
function createGoogleWalletPassHandler(
options: CreateGoogleWalletPassHandlerOptions,
): (req: WalletPassRequest, res: WalletPassResponse) => Promise<void>
options— Resolver + optional save-URL prefix override.
Returns: Handler.
buildZipBuffer(entries)
Build a STORE-method zip Buffer from a list of in-memory file entries.
function buildZipBuffer(entries: ZipFileEntry[]): Buffer<ArrayBufferLike>
entries— Files to embed.
Returns: The complete zip bytes.
crc32(data)
Compute a CRC-32/IEEE checksum (the variant zip uses).
Pure-JS implementation — small enough that pulling in a dependency for this one function would be silly.
function crc32(data: Buffer<ArrayBufferLike>): number
data— Bytes to checksum.
Returns: 32-bit unsigned CRC.
sha1Hex(data)
Compute the SHA-1 hash of arbitrary bytes — re-exported helper used by tests that need to verify manifest hashes.
function sha1Hex(data: Buffer<ArrayBufferLike>): string
data— Bytes to hash.
Returns: Lowercase 40-char hex digest.
Constants
PKPASS_CONTENT_TYPE
Apple .pkpass MIME type.
const PKPASS_CONTENT_TYPE: 'application/vnd.apple.pkpass'
Injection Notes
Runtime Dependencies
node-forge
Both generators cover their vendor's full pass-type range. The Apple
generator accepts all five PassKit styles (eventTicket, boardingPass,
coupon, generic, storeCard) via ApplePassData. The Google
generator selects its pass type via the passType argument
(GoogleWalletPassType) and routes to the matching JWT payload keys —
eventTicket, offer/coupon, loyalty, giftCard, flight, transit,
or generic — defaulting to eventTicket.
Signing material is caller-supplied PEM strings — this package reads no
environment variables and makes NO network calls (signing is fully local).
Store the PEMs as your app's own secrets and load them in your resolver.
Apple: the developer-portal "Pass Type ID" certificate + its private key
(ApplePassCertificates``.password decrypts an encrypted key) and
Apple's WWDR intermediate certificate. Google: a service account
(clientEmail + RSA private key) attached to your Wallet issuer account.