Create a Pass from a Klaviyo Flow Using a Webhook Action

Daniel Baudino

Updated June 3, 2026

TL;DR: Use Klaviyo's native Webhook flow action to call the PassNinja API and issue a pass — no code required.
  • Add a Webhook action to any Klaviyo flow
  • POST to https://api.passninja.com/v1/passes with your template ID and pass fields
  • Map pass fields using Klaviyo liquid tags — no JavaScript needed
  • PassNinja automatically writes the serial number back to the Klaviyo profile

Overview

Klaviyo's native Webhook flow action sends an HTTP POST directly to the PassNinja API. You configure the URL, headers, and request body in the Klaviyo UI — no code required. This is the fastest way to issue a pass from a Klaviyo flow when you don't need conditional logic.

Prerequisites

RequirementDetails
PassNinja accountWith at least one pass template created
Klaviyo accountManager, Admin, or Owner access
Klaviyo integration connectedPassNinja → Integrations → Klaviyo must be connected

You will need three values from PassNinja:

ValueWhere to find it
PASSNINJA_API_KEYPassNinja → Settings → API Keys
PASSNINJA_ACCOUNT_IDPassNinja → Settings → API Keys (format: aid_0x...)
PASSNINJA_TEMPLATE_IDPassNinja → Pass Templates → select template (format: ptk_0x...)

Step 1 — Add a Webhook action to your flow

In Klaviyo's flow builder, click the + button at the point where you want the pass to be created, then choose Webhook.

Good trigger points:

  • Subscribed to List — issue a welcome pass when someone joins
  • Placed Order — issue a post-purchase loyalty pass
  • Custom metric — issue a pass on loyalty enrollment or any business event

Step 2 — Configure the request

FieldValue
MethodPOST
URLhttps://api.passninja.com/v1/passes

Step 3 — Add headers

HeaderValue
X-API-KEYYour PassNinja API key
X-ACCOUNT-IDYour account ID (e.g. aid_0x1a2b3c)
Content-Typeapplication/json

Step 4 — Set the request body

{
  "passTemplate": "ptk_0x4d5e6f",
  "pass": {
    "member-name": "{{ person.first_name }} {{ person.last_name }}",
    "member-email": "{{ person.email }}",
    "phone-number": "{{ person.phone_number|default:'' }}"
  },
  "recipient": {
    "email": "{{ person.email }}",
    "name": "{{ person.first_name|default:'' }}"
  }
}

Replace ptk_0x4d5e6f with your actual template ID.

Replace the keys inside pass with the api_field_name values from your pass template — find these in PassNinja → Pass Templates → select your template → Fields.

Referencing custom Klaviyo profile properties

Use {{ person.properties.your_property_name|default:'' }} to map any custom profile property to a pass field:

{
  "passTemplate": "ptk_0x4d5e6f",
  "pass": {
    "member-name": "{{ person.first_name }} {{ person.last_name }}",
    "member-email": "{{ person.email }}",
    "loyalty-tier": "{{ person.properties.loyalty_tier|default:'Standard' }}",
    "points-balance": "{{ person.properties.loyalty_points|default:0 }}"
  },
  "recipient": {
    "email": "{{ person.email }}",
    "name": "{{ person.first_name|default:'' }}"
  }
}

Step 5 — Save and activate

Save the Webhook action and activate your flow. Klaviyo will send the request to PassNinja each time a profile reaches that step.

How the profile write-back works

After PassNinja creates the pass, it automatically fires a Pass Created event back to Klaviyo. The customer profile is created (or updated) with:

Profile FieldValue
external_idThe pass serial number — used in email/SMS pass links
emailCustomer email (if included on the pass)
phone_numberCustomer phone (if included on the pass)

PassNinja also writes a WalletPass Application Object record in Klaviyo's Custom Objects, linked to the profile via external_id. This record tracks pass state (active, uninstalled, deleted), the download URL, platform, and timestamps.

To link directly to the customer's pass in any subsequent email or SMS, use:

https://passninja.com/p/{{ person.external_id }}

Troubleshooting

Webhook not firing or returning an error

Check the webhook delivery log: Klaviyo → Flows → select your flow → Activity. Look for non-2xx responses and read the response body — PassNinja returns a JSON error message describing the problem.

Common causes:

  1. Wrong API key or account ID in the headers
  2. Pass field keys don't match the api_field_name values in your template — check PassNinja → Pass Templates → Fields
  3. A required field is missing or empty

external_id not set on the profile

  1. Confirm the Klaviyo integration is connected in PassNinja → Integrations → Klaviyo
  2. Allow a few seconds — the write-back fires asynchronously after pass creation
  3. Search for the profile in Klaviyo using the pass serial number

Support

Was this article helpful?
Yes No