Passmint
TemplatesDocsPricing
Log inGet started
Passmint
TemplatesDocsPricingTermsPrivacy

© 2026 Passmint. Built for indie makers.

Getting started

  • Overview
  • Quickstart

API

  • REST API reference
    • Authentication
    • Passes
    • Templates
    • Events
    • Webhooks
    • Errors
  • Webhooks
    • Event types
    • Creating a webhook
    • Payload format
    • Verifying signatures
    • Retries
  • Node.js SDK
    • Configuration
    • Passes
    • Templates
    • Webhook signatures
    • Errors
    • Idempotency

Open source

  • Passmint Package
Real-time events

Webhooks.

Get notified in real time when passes are installed, updated, or removed from a holder's wallet. Webhooks let you react to lifecycle events without polling — just point us at a URL and we'll deliver signed payloads as they happen.

01

Event types

Every webhook delivery includes a type field identifying the event. Subscribe to the ones you care about, or use "*" to receive all of them.

  • pass.created — A new pass was issued
  • pass.updated — A pass's field values or metadata were updated
  • pass.url_viewed — A holder viewed the pass distribution URL
  • pass.downloaded — The .pkpass file was downloaded
  • pass.installed — The pass was added to a holder's wallet
  • pass.removed — The pass was removed from a holder's wallet
  • pass.voided — The pass was voided via the API
02

Creating a webhook

Register an endpoint with POST /v1/webhooks. Provide a url (required) and an events array (required). You can optionally include a description and an enabled flag (defaults to true). Use "*" in the events array to subscribe to all event types.

The signing secret (whsec_xxx) is returned only on creation — store it immediately. You will not be able to retrieve it again.

03

Payload format

Every delivery sends a JSON body with the event metadata and the affected pass:

Headers sent with each delivery:

  • Content-Type: application/json
  • passmint-signature: t=<unix_timestamp>,v1=<hmac_sha256>
  • passmint-event-type: pass.installed
  • User-Agent: passmint-webhooks/1.0
04

Verifying signatures

Every delivery is signed with HMAC-SHA256 using the webhook secret returned at creation time. The passmint-signature header contains a timestamp and signature you should verify before trusting the payload.

The Node SDK handles this for you via webhooks.constructEvent:

The default tolerance is 5 minutes. Signatures older than that are rejected to prevent replay attacks.

05

Retries

Failed deliveries are retried up to 7 times with exponential backoff:

  • Immediate
  • 30 seconds
  • 5 minutes
  • 30 minutes
  • 2 hours
  • 12 hours
  • 24 hours

After 7 failed attempts the delivery status becomes dead. Your endpoint should return a 2xx status within 10 seconds — anything else is treated as a failure.

06

Managing webhooks

Full CRUD is available on the /v1/webhooks resource:

  • GET /v1/webhooks — list all webhooks
  • GET /v1/webhooks/:id — retrieve a single webhook
  • PATCH /v1/webhooks/:id — update url, events, enabled, or description
  • DELETE /v1/webhooks/:id — permanently delete a webhook and its delivery history
07

Monitoring deliveries

Inspect recent delivery attempts for any webhook with GET /v1/webhooks/:id/deliveries. Each delivery record includes the HTTP status, response body (truncated to 2,000 characters), and timestamps — useful for debugging failing endpoints.

Delivery statuses:

  • pending — queued, not yet attempted
  • delivered — your endpoint returned a 2xx
  • failed — attempt failed, will be retried
  • dead — all retry attempts exhausted
curl https://api.passmint.com/v1/webhooks \
  -H "Authorization: Bearer pmk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/passmint",
    "events": ["pass.installed", "pass.removed"],
    "description": "Track wallet installs"
  }'
{
  "id": "evt_abc123",
  "type": "pass.installed",
  "created_at": "2026-04-16T12:00:00.000Z",
  "data": {
    "pass": {
      "id": "pass_xxx",
      "short_id": "abc123",
      "mode": "live",
      "holder_email": "alice@example.com",
      "holder_name": "Alice Johnson",
      "field_values": { "seatNumber": "A12" },
      "voided": false
    },
    "event": {
      "type": "installed",
      "metadata": null
    }
  }
}
import { Passmint } from "@passmint/node"

const passmint = new Passmint({
  apiKey: process.env.PASSMINT_API_KEY!,
})

// In your webhook handler
const event = passmint.webhooks.constructEvent(
  rawBody,
  request.headers["passmint-signature"]!,
  process.env.PASSMINT_WEBHOOK_SECRET!,
)

switch (event.type) {
  case "pass.installed":
    // Handle install
    break
  case "pass.removed":
    // Handle removal
    break
}