This guide focuses on the complete workflow for issuing PassFlow mobile passes that can be added to Apple Wallet and Google Wallet for NFC-based access.
What is PassFlow?
PassFlow is DoorFlow's native service for managing digital credentials that work with Apple Wallet and Google Wallet. PassFlow supports:
- NFC technology - Tap phone to reader (Apple VAS and Google SmartTap)
- Barcode/QR codes - Visual scanning
- Multiple pass types - Access cards, membership cards, event tickets, etc.
Pass Types Supported
PassFlow can issue various types of digital passes:
Access & Membership
Events & Travel
Retail
Key Principles
User Consent is Required
Unlike some credential systems, PassFlow passes cannot be added silently:
- Person must always approve "Add to Wallet"
- User explicitly accepts the pass
- Consistent with Apple and Google wallet security policies
Apple Wallet Limitations
Important: Apple passes cannot be remotely removed from Apple Wallet:
- User must manually remove pass from their wallet
- Deleting the credential in DoorFlow prevents future access but doesn't remove the pass from the device
- This is an Apple Wallet platform limitation, not a DoorFlow limitation
What happens when you delete a PassFlow credential in DoorFlow
Google Wallet Behavior
Google SmartTap passes can be remotely revoked:
- Deleting credential in DoorFlow removes pass from Google Wallet
- More seamless cleanup than Apple
Pass Distribution Methods
Method 1: Email Invitation
DoorFlow automatically emails the pass invitation to the person.
When to use
How it works
Method 2: Your App with Invitation Code
You retrieve the invitation details and present them in your own app.
When to use
How it works
Sequence Diagram
This diagram shows pass issuance triggered from either the DoorFlow UI or via API:
but won't grant access end DoorFlow->>ClientApp: Webhook: credential status 'revoked'
Implementation
Method 1: Email Invitation
Step 1: Create person with email
POST /api/3/people
{
"person": {
"first_name": "Alex",
"last_name": "Chen",
"email": "alex@example.com",
"enabled": true
}
}
Step 2: Create PassFlow credential
POST /api/3/people/{person_id}/credentials
{
"person_credential": {
"credential_type_id": 9,
"enabled": true
}
}
Response:
{
"id": "cred_pf123",
"credential_type_id": 9,
"status": "pending",
"enabled": true,
"person_id": 12345,
"created_at": "2024-01-15T14:25:00Z"
}
Step 3: DoorFlow automatically emails invitation
Person receives email with "Add to Apple Wallet" or "Add to Google Wallet" button. No additional work required.
Method 2: Your App Handles Delivery
Step 1: Create person
POST /api/3/people
{
"person": {
"first_name": "Alex",
"last_name": "Chen",
"enabled": true
}
}
Step 2: Create PassFlow credential
POST /api/3/people/{person_id}/credentials
{
"person_credential": {
"credential_type_id": 9,
"enabled": true
}
}
Step 3: Retrieve pass details
GET /api/3/people/{person_id}/credentials/{credential_id}
Response:
{
"id": "cred_pf123",
"credential_type_id": 9,
"status": "pending",
"wallet_pass_url": "https://wallet.doorflow.com/passes/abc123",
"enabled": true,
"person_id": 12345
}
Step 4: Present "Add to Wallet" in your app
iOS (Apple Wallet):
// Display Apple Wallet button
let passURL = URL(string: "https://wallet.doorflow.com/passes/abc123")!
// Use PKAddPassButton or custom UI
Android (Google Wallet):
// Display Google Wallet button
val passUrl = "https://wallet.doorflow.com/passes/abc123"
// Use Google Wallet button or custom UI
Web:
<a href="https://wallet.doorflow.com/passes/abc123">
<img src="add-to-apple-wallet.svg" alt="Add to Apple Wallet">
</a>
Credential Status Lifecycle
PassFlow credentials go through these statuses:
- pending - Pass created, waiting for person to add to wallet
- active - Person added pass to wallet, credential working
- revoked - Credential removed from DoorFlow, access denied
Monitor via webhooks:
{
"event": "credential.status_changed",
"credential_id": "cred_pf123",
"person_id": 12345,
"old_status": "pending",
"new_status": "active",
"timestamp": "2024-01-15T14:30:00Z"
}
Apple VAS Limitations
Apple Value Added Services (VAS) passes have restrictions
If your use case doesn't fit Apple VAS restrictions
Best Practices
Provide Backup Credentials
Not all users can use mobile passes:
# Issue PassFlow credential (primary)
POST /api/3/people/12345/credentials
{
"credential_type_id": 9,
"enabled": true
}
# Issue PIN (backup)
POST /api/3/people/12345/credentials
{
"credential_type_id": 6,
"value": "******",
"enabled": true
}
Monitor Pass Acceptance
Don't assume pass was added to wallet:
# Check credential status
GET /api/3/people/{person_id}/credentials/{credential_id}
# Or use webhooks (recommended)
POST /api/3/webhooks
{
"url": "https://your-app.com/webhooks/doorflow",
"events": ["credential.status_changed"]
}
Test on Both Platforms
PassFlow works differently on iOS vs Android:
Test checklist
Educate Users
Users need guidance on:
- How to add pass to their wallet
- How to use pass at readers (tap phone)
- What to do if pass doesn't work (use backup PIN)
- How to remove pass when no longer needed (Apple users)
Troubleshooting
Pass stuck in 'pending' status
Person hasn't added pass to wallet yet. Check:
- Did they receive the invitation?
- Do they know how to add passes to their wallet?
- Is wallet app installed and working?
- Try resending invitation
Pass added to wallet but not working at readers
Check these common issues:
-
Credential not synced to readers
- Wait a few minutes for sync
- Check reader is online
-
Person lacks group membership
bashGET /api/3/people/{person_id} # Check group_ids includes appropriate groups -
Person is disabled
bashGET /api/3/people/{person_id} # Check "enabled": true -
Reader doesn't support NFC
- Verify reader has NFC capability
- Check reader is configured for PassFlow
-
Phone NFC is disabled
- User must enable NFC in phone settings
- Test with another NFC-enabled app
How do I update pass information (name)?
Once you update the person's name in DoorFlow it will be passed on to the pass using push notifications automatically.
Can a person have PassFlow pass on multiple wallets?
No. A PassFlow pass can only appear in one wallet. Once the pass has been activated within a wallet the pass invitation will no longer allow the pass to be added to another wallet.
Security Considerations
Pass URLs are Sensitive
Wallet pass URLs should be treated securely:
- Anyone with URL can add pass to their wallet
- Use HTTPS for all pass delivery
- Consider URL expiration if implementing custom delivery
- Don't log pass URLs in plain text
Prevent Unauthorized Pass Sharing
Educate users not to share "Add to Wallet" links:
- Passes should only be added to the authorized person's device
- Sharing pass URLs could grant unauthorized access
- Monitor for multiple passes added from same invitation
Comparison: PassFlow vs HID Mobile Access
| Feature | PassFlow | HID Mobile Access |
| Wallet integration | Apple Wallet, Google Wallet | HID Mobile Access app |
| User experience | Native wallet app | Dedicated HID app |
| Setup complexity | Simpler | More complex |
| Apple support | Limited (VAS restrictions) | Full support |
| Android support | Full support | Full support |
| Remote revocation | Partial (Android only) | Full (both platforms) |
| Best for | Android-focused, simple deployments | Full mobile credential control |
When to choose PassFlow
When to choose HID Mobile Access
Quick Reference
Create PassFlow credential:
POST /api/3/people/{person_id}/credentials
Body: {
"credential_type_id": 9,
"enabled": true
}
Retrieve wallet pass URL:
GET /api/3/people/{person_id}/credentials/{credential_id}
# Returns: { "wallet_pass_url": "https://wallet.doorflow.com/passes/abc123" }
Check credential status:
GET /api/3/people/{person_id}/credentials/{credential_id}
# Returns: { "status": "pending|active|revoked" }
Revoke credential:
DELETE /api/3/people/{person_id}/credentials/{credential_id}
Required OAuth scope: account.person