Priya ships a routine deploy to the ticketing platform's pass service on a Tuesday morning, a week before a festival on-sale expected to move forty thousand tickets. By Wednesday, support has logged three complaints: new buyers can't add their ticket to Apple Wallet. The error in the logs is a signing failure that has nothing to do with Tuesday's code. Every ticket sold last month still opens and scans fine at will call. It's only the passes trying to get signed today that fail, and the certificate behind Priya's signing service quietly turned one year old on Sunday.
That split, old passes fine, new ones dead on arrival, is the specific shape a Pass Type ID certificate takes when it expires. It doesn't look like an outage. It looks like nothing happened, right up until someone tries to do the one thing the certificate was for, and by then Priya has already burned half a morning ruling out her own deploy before she thinks to check the certificate at all.
That's a common first reaction, and it's the wrong instinct to lead with. A certificate expiring produces the same symptom as a dozen other bugs: a failed request with no traffic spike, no crash, nothing a dashboard would flag on its own. Knowing this failure mode exists, and what it looks like from the inside, is most of what shortens that half a morning to five minutes.
What stops working the day it expires, and what doesn't
A Pass Type ID certificate is good for exactly one year from the day Apple issues it, and Apple's own support documentation is direct about the split: "If your certificate expires, passes that are already installed on users' devices will continue to function normally. However, you'll no longer be able to sign new passes or send updates to existing passes." Nothing on the device changes. The pass a customer added in July still opens, still shows its barcode, still scans at the gate in December.
What stops is everything downstream of your signing key. A new customer trying to add a pass hits a server that can no longer produce a valid signature, and gets whatever error handling you wrote for that case, if you wrote any. A loyalty balance that should update after a purchase stays frozen, because pushing that change means signing a new version of the pass, and signing is exactly what an expired certificate can't do. Developers who've hit this and posted about it on Apple's own forums confirm the device side stays quiet too: an expired certificate doesn't trigger Wallet to flag or remove anything already installed. It just stops answering.
This is the WWDR certificate's opposite failure mode, worth naming so you don't chase the wrong one. Apple's WWDR intermediate barely changes and isn't on a per-team clock. Your Pass Type ID certificate is yours, it's annual, and it's the one that actually catches teams off guard.
The error itself rarely says "certificate expired" in plain language. Most signing code calls into OpenSSL or an equivalent library to build the PKCS#7 signature over the pass manifest, and what comes back is a generic signing failure, sometimes with "certificate has expired" buried in a stack trace, sometimes just a nonzero exit code your service wraps in its own error handling. If your signing step logs the raw error rather than swallowing it into a flat "failed to create pass" message, you'll see the real cause in seconds. If it doesn't, you're stuck testing wrong theories, a bad pass.json field, a broken build, a flaky Apple endpoint, before someone thinks to check a date.
One certificate, two jobs
The reason an expired certificate breaks updates and not just new signups comes down to a detail most integrations only learn about once it bites them. Apple's Wallet developer guide states it plainly: "You use the same certificate and private key for sending push notifications as for signing passes." Wallet's update flow depends on your server sending a silent push through Apple's Push Notification service whenever something on a pass changes, which is what tells the device to call back and ask for the new version. That push authenticates with your Pass Type ID certificate, the identical file that signs the .pkpass bundle itself.
So a single expired certificate doesn't cost you one capability. It costs you two at once, and they fail differently. Signing failures show up immediately and loudly, because a customer is standing there watching an "add to wallet" button do nothing. Push failures are quieter. The push itself can't go out, so no device even gets told to check in, and a pass that should have updated just sits there looking current while it silently isn't. Two different symptoms, one root cause, and nothing in either error message points back at the certificate.
Walk the full update flow and you can see exactly where it stops. A device registers for updates on install, posting its push token to your web service. Later, something changes, a gate number, a loyalty balance, and your server sends an APNs push with an empty payload, authenticated by the Pass Type ID certificate as the topic. The device wakes up, calls your server's getSerialNumbers endpoint to ask what changed, and requests the updated pass, which your server signs and returns. An expired certificate breaks that chain at two separate points rather than one: the push at the start can't authenticate, and even in the rare case a stale connection lets one through, the signing step at the end fails anyway. There's no partial success to find, because both ends of the same flow depend on the same file.
Why the outage takes weeks to notice
A server that goes down pages someone within minutes. A certificate that expires doesn't, because most of what it breaks fails one request at a time instead of all at once. Your health check still returns 200. Your database is fine. The only thing wrong is that a specific downstream call, sign this manifest, authenticate this push, starts throwing, and unless you're specifically watching for that error, it gets logged and moves on.
What actually surfaces the problem is usually a support ticket, not a monitor. A customer notices their punch card isn't filling up. A gate agent notices a boarding pass showing yesterday's time. Each one looks like an isolated bug, and it can take several of them landing on the same week before anyone connects them back to a certificate that turned over a year ago and has been broken ever since, with nothing in between to announce it. By the time that connection gets made, you're not fixing one failed request, you're explaining to a support team why the last several weeks of tickets share a cause nobody flagged.
The math works against you here too. New pass installs are usually a small slice of total traffic next to scans and reads of passes already issued, so a signing endpoint that's been failing for two weeks can still leave your overall error rate looking flat on a dashboard tuned for aggregate volume. Many teams only catch it once someone builds a specific alert on that one endpoint, rather than trusting a general health check to notice a narrow, consistent failure buried in a much larger and mostly healthy request volume.
A renewal that failed quietly for a month
This pattern, a routine renewal breaking silently and staying broken until something forces the issue, isn't unique to wallet passes. On December 26, 2025, the SSL certificate covering Bazel's release and registry domains expired at 07:35 UTC, and builds across the ecosystem started failing with certificate validation errors. Google's postmortem traced the actual failure back almost two months earlier: a subdomain was removed from DNS on October 30, and when the automated renewal process ran around November 26, it failed repeatedly because that now-unreachable subdomain was still listed on the certificate. Every domain on a certificate has to answer before a renewal is issued, so the renewal simply never completed, and nothing about that failure generated an alert.
Nobody found out until the expired certificate started breaking builds on a holiday week, and it took about 13 hours to get a new certificate live, from the first user report to a working certificate propagated across every frontend. The postmortem includes an uncomfortable detail: an earlier, similar outage had already left an action item to add alerting on certificate renewal failures, and that item sat unprioritized until this exact failure mode repeated itself. A team that had already been burned by the same class of bug still missed the second one, because the fix lived on a backlog rather than in a running check.
A Pass Type ID certificate doesn't have DNS dependencies or an automated renewal that can fail behind the scenes. It has something arguably easier to miss: no renewal process at all. Apple emails a reminder roughly 30 days out, to whatever Apple ID requested the certificate in the first place, which is fine until that's an account nobody checks, a shared login, or someone who left the team eight months ago. The Bazel outage happened despite automation. A Pass Type ID certificate expires by default unless a specific person acts on an email, which is a lower bar to miss, not a higher one.
Expiration is not revocation
It's worth being precise here, because the two failure modes sound similar and aren't. Apple's own comparison draws the line clearly: an expired certificate blocks future signing and updates while every already-installed pass keeps working, but "if your certificate is revoked, your passes will no longer function properly." Revocation isn't something that happens on a clock. It happens when someone with account access deletes a certificate from Apple's developer portal, usually while cleaning up a list of old ones.
The practical upshot is that an expired certificate is a signing failure to fix on your own timeline, not an incident where you need to explain to every customer why their pass suddenly stopped scanning. Treat the two differently. If you find an old certificate sitting in your developer account and you're not sure whether it's live, confirm which one your production signing service actually loads before you revoke anything. Revoking the wrong row turns a certificate that was merely aging into one that breaks passes on people's phones today.
Confirming which certificate is actually live is usually one command, not a guess. Compare the fingerprint or serial number your signing service reports against what's listed in the developer portal for that Pass Type ID, and you know exactly which row is safe to touch and which one isn't. Teams that skip this step tend to be the same ones cleaning out a certificate list that's grown unreadable after several years of expirations nobody removed, where an old certificate and the current production one look identical at a glance.
Getting back to green
Recovering starts in Certificates, Identifiers & Profiles in the Apple Developer portal, under the same Pass Type ID, since the identifier itself doesn't expire, only the certificate tied to it. There's no renew button. You generate a new certificate signing request, submit it against that Pass Type ID, and Apple issues a fresh certificate you import and export as a new .p12 alongside its private key. Deploy that to replace the expired one in your signing service, and both jobs resume immediately: new passes sign again, and the next push you send authenticates and reaches devices. Passes that missed updates while the certificate sat expired catch up on their next successful push. Nobody needs to reinstall anything.
Deploying the replacement is where a second, avoidable mistake shows up. A .p12 this important is rarely stored in one place. It's often copied into a secrets manager, a CI pipeline's encrypted variables, and a local .env file a developer used once to debug something, and updating only the first of those leaves a staging environment or a background worker still signing with the certificate that just expired. Before you call the rotation done, grep your infrastructure for every place that file lives, not just the one your main signing service reads from. Sign one test pass against a Pass Type ID you don't use in production first, and confirm it installs cleanly, before you push the new certificate everywhere the old one was.
The part worth automating is catching this before a customer does. A certificate's expiration date is a plain field on the file itself, so check it on a schedule instead of trusting a single inbox:
openssl pkcs12 -in pass-type-id.p12 -nocerts -nodes -passin pass:yourpassword | \
openssl x509 -noout -enddate
# notAfter=Sep 20 23:59:59 2027 GMTRun that in a scheduled job that posts to a channel the whole team watches, not a calendar entry on one engineer's account, and Apple's 30-day email stops being the only warning you get. If you'd rather not own that whole renewal cycle yourself, Passmint holds your Pass Type ID certificate, tracks its expiry, and surfaces the date directly instead of leaving it buried in an email to an Apple ID nobody remembers the password for.
Primary sources
Common questions
Technical content writer, Passmint
Julio is a technical content writer at Passmint. He writes about Apple PassKit, the Google Wallet API, and what breaks when wallet passes meet production traffic.
More from Julio Song →