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 Signature header
  • Retries 3x with exponential backoff
  • Configurable at organizer level (all events) or per-event

Relevant event types

EventTriggerPayload includes
checkin.createdAttendee checked inattendee_id, email, name, event_id, check_in_list_id
checkin.deletedCheck-in reversedattendee_id, check_in_list_id
order.createdTicket purchasedemail, name, totals, attendees[], order_items[]
attendee.createdAttendee added to eventemail, 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 Signature header
  • Parse JSON body
  • Route by event_type:
    • checkin.created → look up member by attendee email → create check-in (method: event) with 4-hour dedup → link hiEventsAttendeeId
    • order.created → look up member by order email → link hiEventsAttendeeId if not set
  • Return 200 for all events (same as Square/Stripe handlers)

3. Processing logic

File: guild/src/lib/hi-events.ts

  • verifyHiEventsSignature(payload, signature, secret) — HMAC-SHA256
  • processEventCheckIn(attendeeEmail, attendeeId, shopId) — member lookup + dedup + check-in creation
  • linkHiEventsAttendee(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