Issue tamper-proof attendance credentials at venue check-in. Let fans carry verified event history as portable proofs for loyalty rewards, presales, and exclusive access.
Use this file to discover all available pages before exploring further.
Traditional event tickets are one-time-use and forgotten after the show. AIR Kit lets you transform every venue scan into a permanent, portable attendance credential — proof the fan was there, reusable for loyalty rewards, presale access, partner discounts, and cross-brand partnerships.
Your venue scanner calls your backend on each valid scan. The backend issues via Issue on Behalf — the fan does nothing, no wallet open, no UX friction at the door.
// venue-checkin.jsconst { getPartnerJwt } = require('./lib/jwt');async function issueAttendanceCredential({ fanEmail, eventDetails }) { const token = await getPartnerJwt(fanEmail); const res = await fetch('https://api.sandbox.mocachain.org/v1/credentials/issue-on-behalf', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-partner-auth': token, }, body: JSON.stringify({ issuerDid: process.env.ISSUER_DID, credentialId: process.env.ATTENDANCE_CREDENTIAL_ID, credentialSubject: { eventId: eventDetails.id, eventName: eventDetails.name, venue: eventDetails.venue, attendedAt: new Date().toISOString(), ticketTier: eventDetails.ticketTier, // "General" | "VIP" | "Backstage" organizerId: process.env.ORGANIZER_ID, }, onDuplicate: 'ignore', // one credential per event per fan }), }); if (!res.ok) throw new Error(`Attendance issuance failed: ${res.status}`); const { coreClaimHash } = await res.json(); return coreClaimHash;}// Called by your ticketing system on each valid scanapp.post('/api/checkin', async (req, res) => { const { fanEmail, eventId } = req.body; const event = await getEventDetails(eventId); const hash = await issueAttendanceCredential({ fanEmail, eventDetails: event }); res.json({ success: true, coreClaimHash: hash });});
Step 3 — Auto-upgrade fans to loyalty tiers after N events
// loyalty-tier-check.js — called after each attendance credential issuanceasync function checkAndIssueLoyaltyTier(fanEmail) { const attendedCount = await getAttendanceCount(fanEmail); // your DB if (attendedCount === 5) await issueLoyaltyTier({ fanEmail, tier: 'Loyal Fan' }); if (attendedCount === 20) await issueLoyaltyTier({ fanEmail, tier: 'Super Fan' });}// issueLoyaltyTier uses the same Issue on Behalf pattern — see AIR for Loyalty guide
The key advantage for events: fans never interact with the credential system at the door. They scan their ticket as normal, the credential lands in their AIR Account in the background, and they use it the next time they want a reward or presale.
1
Fan scans ticket at the door
No app to open, no wallet prompt. Exactly the same experience as today.
2
Your backend issues the attendance credential
Issue on Behalf fires silently. The fan’s AIR Account receives the credential on-chain.
3
Fan opens the app the next day
Sees a notification: “You earned a Verified Attendee credential for Coachella 2025.”
4
Fan uses the credential
One tap to register for the presale, claim a merchandise discount, or prove their fan tier to a partner brand.