Quickstart
Create a customer, issue a pass, and record a purchase with the current SDK contract.
Prerequisites
- Node.js 18 or newer
- A WalletHero API token
- Existing workspace, project, and pass-template UUIDs
Install and initialize
npm install @wallethero/sdkimport { WalletHero } from "@wallethero/sdk";
const walletHero = new WalletHero({
apiToken: process.env.WALLETHERO_API_TOKEN!,
});
if (!(await walletHero.ping())) {
throw new Error("Could not connect to WalletHero");
}
const { data: user } = await walletHero.me();
console.log(`Connected as ${user.email}`);Create the customer
Identity, consent, loyalty enrollment, and custom fields are stored on the client record, not the pass.
const workspaceId = "workspace-uuid";
const projectId = "project-uuid";
const templateId = "template-uuid";
const { data: customer } = await walletHero.clients.create(workspaceId, {
workspace_id: workspaceId,
first_name: "Jane",
last_name: "Customer",
email: "[email protected]",
marketing_consent: true,
marketing_consent_text: "I agree to receive loyalty updates.",
loyalty_program_enabled: true,
custom_fields: {
member_number: "M-1042",
preferred_store: "Downtown",
},
});Issue the pass
const { data: pass } = await walletHero.passes.create({
workspace_id: workspaceId,
project_id: projectId,
pass_template_id: templateId,
client_id: customer.id,
});
console.log("Pass ID:", pass.id);
console.log("Apple Wallet:", pass.apple_pass_url);
console.log("Google Wallet:", pass.google_pass_url);You can combine the preceding steps by providing client_identity instead of client_id. The API creates or reuses a matching client in the workspace.
const { data: pass } = await walletHero.passes.create({
workspace_id: workspaceId,
project_id: projectId,
pass_template_id: templateId,
client_identity: {
email: "[email protected]",
first_name: "Alex",
marketing_consent: true,
custom_fields: { member_number: "M-1043" },
},
});Record activity
Event convenience methods take positional amount and currency arguments, followed by optional metadata.
await walletHero.events.recordPurchase(pass.id, 25, "PLN", {
external_id: "receipt-1842",
source: "pos",
metadata: { store: "Downtown" },
});
await walletHero.events.recordCheckIn(pass.id, {
source: "store-downtown",
});For normalized transaction analytics and loyalty side effects, use the transactions service:
await walletHero.transactions.create({
workspace_id: workspaceId,
client_id: customer.id,
external_id: "receipt-1842",
amount: 25,
currency: "PLN",
source: "pos",
transaction_timestamp: new Date().toISOString(),
});Update customer fields
Pass display placeholders resolve client-owned custom fields. Update them through ClientsService so field-change events and downstream automation run correctly.
await walletHero.clients.mergeCustomFields(workspaceId, customer.id, {
preferred_store: "Airport",
});
await walletHero.passes.sendNotification(
pass.id,
"Your preferred store was updated.",
);Template placeholders
Current pass templates use these placeholder families:
${client.first_name}
${client.email}
${custom_fields.member_number}
${wallet.points}
${wallet:bonus.points}
${loyalty.tier}
${loyalty.referral_code}${wallet.points} targets the default wallet. ${wallet:<code>.points} targets a specific wallet type. The retired ${loyalty.points} placeholder is not supported.
Complete example
import { WalletHero, WalletHeroError } from "@wallethero/sdk";
async function main() {
const walletHero = new WalletHero({
apiToken: process.env.WALLETHERO_API_TOKEN!,
});
const workspaceId = process.env.WALLETHERO_WORKSPACE_ID!;
const projectId = process.env.WALLETHERO_PROJECT_ID!;
const templateId = process.env.WALLETHERO_TEMPLATE_ID!;
const { data: customer } = await walletHero.clients.create(workspaceId, {
workspace_id: workspaceId,
email: "[email protected]",
first_name: "Jane",
loyalty_program_enabled: true,
});
const { data: pass } = await walletHero.passes.create({
workspace_id: workspaceId,
project_id: projectId,
pass_template_id: templateId,
client_id: customer.id,
});
await walletHero.events.recordPurchase(pass.id, 25, "PLN", {
external_id: "receipt-1842",
});
console.log(pass.apple_pass_url, pass.google_pass_url);
}
main().catch((error) => {
if (error instanceof WalletHeroError) {
console.error(error.status, error.code, error.message);
} else {
console.error(error);
}
process.exitCode = 1;
});