FOR DEVELOPERS

Add Apple Wallet passes to your app

Send JSON. Receive a signed .pkpass file. AddPass handles Apple Wallet pass generation and signing, so you can focus on your application.

Use one endpoint to create branded generic passes with custom text, colors, images, barcodes, and location fields. Return the pass file directly or request a temporary download link for your delivery flow.

Start in the free developer sandbox, generate your first pass, and choose a paid plan when you are ready for more volume. API keys and the full reference are available in the developer portal.

Building with an AI coding agent?

Give your agent the steps to connect AddPass and generate your first Apple Wallet pass.

Read the quick start
# Add Apple Wallet passes to this project with AddPass

Help me integrate AddPass into this project's existing architecture. Inspect the
framework and server structure first, then implement the smallest working flow:
a server-side request that generates a signed Apple Wallet pass and lets a user
download it. Reuse the project's conventions and explain how to test the result.

## Account setup (human step)

1. Open https://app.addpass.io/sign-up/SANDBOX and create an account or continue
   with Google. If you already have developer access, use
   https://app.addpass.io/developer after signing in.
2. In the developer portal, create an API key and save the full key when shown.
3. Configure `ADDPASS_API_KEY` in your project's server-side environment / secret
   store. Keep local secret files out of Git. Do not put the key in browser code,
   public environment variables, URLs, chat messages, or logs.
4. If the user still needs a key, build the integration using the environment
   variable and pause the live test until they configure it. Do not create an
   account, buy a plan, or invent a key on their behalf.

Start with the free developer sandbox; no credit card is required. Sandbox passes
are for testing and new sandbox accounts receive visible sandbox markings. Check
current allowances in the portal. Choose a paid developer plan for production use.

## API contract

- POST `https://app.addpass.io/api/v1/generate`
- `Authorization: Bearer <ADDPASS_API_KEY>`
- `Content-Type: application/json`
- `Accept: application/json` returns a JSON object with `passId`, `passUrl`,
  `expiresAt`, and `message`.
- `Accept: application/vnd.apple.pkpass` returns the signed binary `.pkpass` file.
- `primaryText` is required (up to 36 characters). A template ID is not required.
- AddPass generates and signs generic Apple Wallet passes. No Apple signing
  certificate needs to be supplied for this API integration.

Minimal request body:

```json
{
  "primaryText": "My First Pass",
  "logoText": "My App",
  "backgroundColor": "#211c38",
  "foregroundColor": "#FFFFFF",
  "labelColor": "#FFFFFF",
  "barcode": {
    "format": "qr",
    "message": "https://example.com/membership/demo"
  }
}
```

The barcode encodes a value; your application implements any check-in,
membership validation, or redemption behavior. Do not assume this API supplies
those systems, native Google Wallet API issuance, or updates to already-installed
passes. Generated .pkpass files can be imported by compatible Google Wallet
clients; test compatibility on your target devices.
Use the field reference in https://app.addpass.io/developer for additional fields.

## First request (server-side JavaScript / TypeScript)

Adapt this to the project's server runtime rather than creating a separate server
if one already exists. Node.js 20+ provides `fetch`.

```js
const apiKey = process.env.ADDPASS_API_KEY;
if (!apiKey) throw new Error('Configure ADDPASS_API_KEY on the server first.');

const response = await fetch('https://app.addpass.io/api/v1/generate', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
  body: JSON.stringify({
    primaryText: 'My First Pass',
    logoText: 'My App',
    backgroundColor: '#211c38',
    foregroundColor: '#FFFFFF',
    labelColor: '#FFFFFF',
    barcode: { format: 'qr', message: 'https://example.com/membership/demo' },
  }),
});

if (!response.ok) {
  const details = await response.json().catch(() => ({}));
  throw new Error(`AddPass ${response.status}: ${details.error || 'Request failed'}`);
}

const { passUrl } = await response.json();
if (!passUrl) throw new Error('AddPass did not return a download link.');
// Return this link to the requesting user through your own server route.
```

The download URL is short-lived (currently approximately 15 minutes). `expiresAt`
is the stored file's retention deadline, NOT the signed URL's expiry. Do not
persist `passUrl` as a permanent membership link. For durable delivery, request
the binary response and store/serve the file through your own application.

## Integrate and verify

- Protect your server route using the project's authentication and validate its
  inputs. Do not expose an unrestricted proxy that spends your API allowance.
- Show an explicit "Download Wallet pass" action after success, with loading and
  error states. Use the actual response URL; do not fabricate a pass or URL.
- A failed authentication request (401), access/quota error (402/403), validation
  error (400), or rate limit (429) should show a useful message. Do not repeatedly
  retry a generation request automatically: another request can consume quota.
- Make one live request after the key is configured, then open the generated
  pass on an iPhone and confirm it can be added to Apple Wallet. Report separately
  whether API generation and on-device installation were actually tested.
- Keep the first integration small. Add custom branding and application-specific
  fields after the minimal flow works.

Public API overview: https://www.addpass.io/api
Developer portal and field reference: https://app.addpass.io/developer
Download the Markdown guide
import { writeFile } from 'node:fs/promises';

const payload = {
  primaryText: 'Summer Gala',
  headerLabelRight: 'Admit One',
  backgroundColor: '#0F1219',
  thumbnailURL: 'https://cdn.example.com/passes/gala.png',
  barcode: { 
  	format: 'qr',
    message: 'https://example.com/tickets/12345'
  },
};

const response = await fetch('https://app.addpass.io/api/v1/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_KEY_HERE',
    'Content-Type': 'application/json',
    'Accept': 'application/pkpass',
  },
  body: JSON.stringify(payload),
});

if (!response.ok) {
  throw new Error('Generation failed');
}

const buffer = Buffer.from(await response.arrayBuffer());
await writeFile('summer-gala.pkpass', buffer);

Sample JSON

Start with the example below and replace the sample values with your own data. Use a generic pass to show event details, membership information, or a QR code that links to your own check-in flow. Your application controls what the barcode does.

Choose your response: use Accept: application/pkpass for the signed file, or Accept: application/json for a temporary download link. Keep your API key on your server.

AddPass handles signing for passes generated through the API. Get your key and the full field reference in the developer portal, then test a pass on an iPhone before rolling out your integration.
{
  "backgroundColor": "#0F1219",
  "foregroundColor": "#FFFFFF",
  "labelColor": "#FFFFFF",
  "primaryText": "Your Event Name",
  "headerLabelRight": "Admit",
  "headerTextRight": "One",
  "secondaryLabelLeft": "Date",
  "secondaryTextLeft": "August 24, 2025",
  "secondaryLabelRight": "Doors",
  "secondaryTextRight": "6:30 PM",
  "auxiliaryLabelLeft": "Seat",
  "auxiliaryTextLeft": "B12",
  "auxiliaryLabelRight": "Gate",
  "auxiliaryTextRight": "North Entrance",
  "backFields": [
    {
      "label": "Support",
      "value": "support@yourdomain.com"
    },
    {
      "label": "Terms",
      "value": "https://yourdomain.com/terms"
    },
    {
      "label": "Help Desk",
      "value": "(555) 123-9876"
    }
  ],
  "barcode": {
    "format": "qr",
    "message": "https://yourdomain.com/check-in/{{token}}"
  }
}
Ideas into passes

Build with the API

Start with a use case. Make it part of your app.