Hi.Events Webhook Integration
Context
Guild needs to track event attendance for members. Hi.Events is the ticketing/event platform. The integration connects Hi.Events webhooks to Guild’s existing check-in and member systems, enabling automatic attendance tracking and (future) bonus points for event participation.
Customers buy from Square POS first → become Guild members → attend events via Hi.Events. The join key is email address (present in both Hi.Events attendee data and Guild member records).
Hi.Events Webhook System
Hi.Events sends signed POST requests with this structure:
{
"event_type": "checkin.created",
"event_sent_at": "2026-03-30T12:00:00Z",
"payload": { /* entity data */ }
}- Signed with HMAC-SHA256 via
Signatureheader - Retries 3x with exponential backoff
- Configurable at organizer level (all events) or per-event
Relevant event types
| Event | Trigger | Payload includes |
|---|---|---|
checkin.created | Attendee checked in | attendee_id, email, name, event_id, check_in_list_id |
checkin.deleted | Check-in reversed | attendee_id, check_in_list_id |
order.created | Ticket purchased | email, name, totals, attendees[], order_items[] |
attendee.created | Attendee added to event | email, name, product, order, event_id |
Payload details
checkin.created payload:
{
"id": 123,
"attendee_id": 456,
"check_in_list_id": 789,
"product_id": 10,
"event_id": 20,
"short_id": "ABC123",
"created_at": "2026-03-30T12:00:00Z",
"attendee": {
"id": 456,
"email": "member@example.com",
"first_name": "Jane",
"last_name": "Doe",
"status": "active",
"public_id": "...",
"product": { "title": "General Admission", "..." : "..." }
}
}order.created payload:
{
"id": 100,
"email": "member@example.com",
"first_name": "Jane",
"last_name": "Doe",
"total_gross": 2500,
"currency": "USD",
"status": "COMPLETED",
"attendees": [
{ "id": 456, "email": "member@example.com", "..." : "..." }
]
}Implementation Plan
1. Add event check-in method
File: guild/src/collections/CheckIns.ts
Add 'event' to the method select field options. Distinguishes Hi.Events-sourced check-ins from NFC/QR/phone/manual.
2. Webhook handler
File: guild/src/app/api/webhooks/hi-events/route.ts
Follows existing Square/Stripe webhook pattern:
- Verify HMAC-SHA256 signature from
Signatureheader - Parse JSON body
- Route by
event_type:checkin.created→ look up member by attendee email → create check-in (method:event) with 4-hour dedup → linkhiEventsAttendeeIdorder.created→ look up member by order email → linkhiEventsAttendeeIdif not set
- Return
200for all events (same as Square/Stripe handlers)
3. Processing logic
File: guild/src/lib/hi-events.ts
verifyHiEventsSignature(payload, signature, secret)— HMAC-SHA256processEventCheckIn(attendeeEmail, attendeeId, shopId)— member lookup + dedup + check-in creationlinkHiEventsAttendee(memberEmail, hiEventsAttendeeId)— link member record
4. Environment
HI_EVENTS_WEBHOOK_SECRET— HMAC signing secret from Hi.Events
Decisions
- Non-member attendees — silently ignore. The data lives in Hi.Events already; a “who attended but isn’t a member” report can query Hi.Events API and diff against Guild members later. No new collection.
- Bonus points — skip entirely. Check-in records are the deliverable. Points can be retroactively awarded from existing check-in data when the feature hits the roadmap.
- Shop resolution — default to first shop in org. Dungeon Books is one shop. Multi-shop mapping (Hi.Events event ID → shop) can come later.
References
- Hi.Events source: HiEventsDev/Hi.Events
- Webhook dispatch:
backend/app/Services/Infrastructure/Webhook/WebhookDispatchService.php - Event types enum:
backend/app/Services/Infrastructure/DomainEvents/Enums/DomainEventType.php - Spatie webhook-server config:
backend/config/webhook-server.php