Automate the pass lifecycle three ways: Flow invocable actions (no code), Apex (in-org code), and the REST API (external systems). All three drive the same engine and the same records.
Flow invocable actions
| Action | Inputs | What it does |
|---|---|---|
| Generate Pass | recordId, templateName, sendEmail | Creates the pass and writes the signed add-to-wallet URL to the record. |
| Send Message | passId | recordId, message | Push notification to one pass; use Bulk Actions for segments. |
| Switch Template | passId, templateName | Changes an installed pass's design in real time. |
| Expire Pass | passId, expiryDate | Sets or clears expiry; expired passes move to the wallet's expired section. |
Apex — upsertPasses and the PassRequest object
The core Apex entry point handles both creation and updates of digital passes:
// Build the request
PassRequest req = new PassRequest();
req.templatePassId = template.Id; // Template Pass record
req.passDetails = new List<String>{ ... }; // ordered per Template Pass Field Content
req.passBarcodes = new List<String>{ ... }; // ordered per Template Barcode
req.passSendToEmails = new List<String>{ contact.Email };
req.whatId = contact.Id; // merged into the email template
// req.passId = existingPassId; // include to UPDATE instead of create
KemicardService.upsertPasses(new List<PassRequest>{ req });
- Ordering is strict: values in
passDetailsandpassBarcodesmust match the Order defined on the Template Pass Field Content and Template Barcode records. - Updates: include
passIdand the server regenerates the pass and pushes the change to the member's wallet via APNs / Google Wallet API. - Optional inputs:
passLocationDetails(name, latitude, longitude, altitude) andattachmentName. - All entry points are bulk-safe and respect the running user's CRUD/FLS.
Prefer clicks over code? The same pipeline is exposed as the Generate Pass invocable action for Flow — see the Flow Integration & Apex Action guide.
REST API
Base URL and bearer-token credentials are issued during onboarding. All endpoints are HTTPS-only.
| Endpoint | Method | Purpose |
|---|---|---|
/v1/passes | POST | Issue a pass for a record + template; returns the signed add-to-wallet URL. |
/v1/passes/{id} | GET | Pass status: installed, removed, last updated, last scanned. |
/v1/passes/{id} | PATCH | Update fields, switch template, or trigger a push. |
/v1/passes/{id} | DELETE | Revoke the pass; the wallet copy is invalidated. |
/v1/webhooks | POST | Register a listener for pass events. |
Webhook events
{
"event": "pass.scanned",
"passId": "kc_9f27ab",
"recordId": "003XXXXXXXXXXXX",
"template": "Gold_Member",
"timestamp": "2026-07-24T16:02:11Z",
"meta": { "scanMethod": "qr", "station": "Gate A" }
}
Events: pass.installed, pass.updated, pass.scanned, pass.removed. Deliveries are signed; verify the signature header before trusting payloads.
Error handling
- 401 Unauthorized — named credential password wrong or user reset; re-enter credentials (see Troubleshooting).
- 409 Conflict — provisioning mismatch; verify Org ID and licensing.
- 429 Too Many Requests — back off; coordinate very large batches with support.
Getting API credentials
- Request REST access from your account manager — credentials are issued per org (sandbox and production separately).
- Store the bearer token in a protected credential store (Named Credential, secrets manager); never hard-code it.
- Rotate tokens on your normal secret-rotation cadence; old tokens can be revoked without downtime.
Rate limits & batching
- Sustained request rates are generous for record-triggered use; for bursts above ~50 requests/second, use Bulk Actions or coordinate a send window with support.
- Batch endpoints accept arrays of record IDs for issuance — prefer one batched call over hundreds of singles.
- Webhook deliveries retry with exponential backoff for 24 hours; make your listener idempotent on
passId + event + timestamp.
API FAQ
- Can I call the REST API from Apex? You can, but in-org use is better served by the invocable actions — they respect CRUD/FLS and avoid callout limits.
- Is there a sandbox base URL? Yes — sandbox credentials point at a staging endpoint so tests never touch production passes.
- How do I test webhooks locally? Register a tunnel URL (e.g., a request-bin) as your listener in sandbox, inspect payloads, then move the subscription to your production endpoint.
