# PerkPass > Issue and update Apple Wallet and Google Wallet passes with a single HTTP request — no certificates, no signing, no wallet infrastructure to maintain. PerkPass is a hosted API for creating loyalty cards, event tickets, coupons, and membership passes that install into Apple Wallet (`.pkpass`) and Google Wallet. You POST JSON and get back installable passes plus a shareable hosted page; updates push to devices via PUT and fire lock-screen notifications on both wallets. ## Pages - [Home](/): What PerkPass is, how the API works, features, pricing preview, and FAQ. - [Pricing](/pricing): Free, Pro, and Enterprise plans with full feature comparison. - [Docs](/docs): API reference — authentication, POST /api/passes, GET/PUT /api/passes/:serial, GET /api/auth/usage, field schemas, and error codes. - [Changelog](/changelog): Release notes and product updates. ## Optional - [Log in](/login): Account sign-in. - [Sign up](/signup): Create a free account and get an API key. ## API quickstart Base URL: `https://perkpass.co.uk` Auth: `Authorization: Bearer pk_live_` ### Create a pass — POST /api/passes ``` curl -X POST https://perkpass.co.uk/api/passes \ -H "Authorization: Bearer pk_live_" \ -H "Content-Type: application/json" \ -d '{ "organizationName": "Bayroast Coffee", "logoText": "Bayroast Coffee", "barcodeValue": "MEMBER-12345", "barcodeFormat": "QR", "colorPreset": "dark", "headerFields": [{ "key": "points", "label": "POINTS", "value": "1,250" }], "primaryFields": [{ "key": "card", "label": "CARD", "value": "Coffee Rewards" }], "secondaryFields": [{ "key": "tier", "label": "TIER", "value": "Gold" }], "expirationDays": 365 }' ``` Response: `{ serialNumber, applePass (base64 .pkpass), googleSaveUrl, shareUrl }`. ### Update a pass — PUT /api/passes/:serial Send the full pass body. Set `changeMessage` on any field to fire a lock-screen banner when that field's value changes — `%@` is replaced with the new value. Identical bodies are no-ops (no push, no quota cost). ``` curl -X PUT https://perkpass.co.uk/api/passes/ \ -H "Authorization: Bearer pk_live_" \ -H "Content-Type: application/json" \ -d '{ "organizationName": "Bayroast Coffee", "barcodeValue": "MEMBER-12345", "barcodeFormat": "QR", "headerFields": [{ "key": "points", "label": "POINTS", "value": "1,300", "changeMessage": "You hit %@ points. Free coffee unlocked!" }], "primaryFields": [{ "key": "card", "label": "CARD", "value": "Coffee Rewards" }] }' ``` Response: `{ serialNumber, lastUpdated, notifiedDevices, unchanged, apple, google, changedFields, googleMessage? }`. Identical bodies return `unchanged: true` with `notifiedDevices: 0` and do not count against quota. PUT bodies must NOT include `serialNumber` or `authenticationToken` (server-owned, returns 400). ### Fetch a pass — GET /api/passes/:serial ``` curl https://perkpass.co.uk/api/passes/ \ -H "Authorization: Bearer pk_live_" ``` Response: `{ serialNumber, passJson, createdAt, updatedAt, shareUrl, googleSaveUrl }`. ### Legacy binary endpoint — POST /api/pkpass Same handler as `/api/passes` but streams the raw `application/vnd.apple.pkpass` binary by default. Serial and Google save URL ride on `X-Serial-Number`, `X-Google-Save-Url`, and `X-Pass-Url` response headers. Add `?format=json` to get the JSON envelope; conversely, `/api/passes?format=pkpass` streams the binary. ### Public Google Wallet redirect — GET /api/passes/:serial/google 302 redirects to the current Save to Google Wallet link. Public (no auth) — use as a stable "Add to Google Wallet" button target. ### Hosted share page — /p/:serial Device-aware install page. Auto-detects iOS, Android, or desktop and shows the right button (QR fallback on desktop). ## Field reference (essentials) - `barcodeValue` + `barcodeFormat` (required) — `QR | PDF417 | Aztec | Code128`. barcodeValue max 512 chars. - `organizationName` — issuer name; shown as notification title. Falls back to `logoText`. - `logoText` — text next to the logo. At least one of `logoText`, `primaryFields`, or `title` is required. - `description` — accessibility text (not visible). Defaults to `logoText`. - `colorPreset` — `dark | blue | green | red | purple | orange`. Pro: `color` (or `customColor`) hex e.g. `#1e40af`. - `headerFields`, `primaryFields`, `secondaryFields`, `backFields` — arrays of `{ label, value, key?, changeMessage? }`. `key` is auto-assigned if omitted. - `locations` — up to 10 `{ latitude, longitude, altitude?, relevantText? }`. Lock-screen geofence (Apple + Google). - `expirationDate` (ISO) or `expirationDays` (1–3650). - `sharingProhibited` — defaults to `true`. Hides Apple Wallet share button. - Pro images (HTTPS URL or `data:image/png;base64,...`): `logoURL`, `iconURL`, `thumbnailURL`, `stripURL`. - Legacy aliases: `title`, `cardLabel`, `label`, `value` — map to primary/secondary fields when those arrays aren't set. ## Send a custom notification Seed a `backFields` "notification anchor" on POST, then PUT a new value with `changeMessage: "%@"` to push that text as a lock-screen banner. ## Plans - Free: 1,000 passes/month. - Pro: 100,000 passes/month + custom color/logo/images. POST counts; unchanged PUTs are free.