Skip to main content

Event RSVP

Handle event attendance through RSVP responses, track attendees, and manage user participation in scheduled events.

Overview

The RSVP system allows users to respond to event invitations with three status types:
  • Going: Confirmed attendance
  • Interested: Considering attendance
  • Not Going: Declined invitation
Each event tracks RSVP counts and provides APIs to manage responses and query attendees.

RSVP Response Types

StatusDescriptionImpact
GoingUser will attendCounted in rsvpCount, included in attendee list
InterestedUser might attendCounted in interestedCount, separate from attendees
Not GoingUser won’t attendRecorded but not counted in attendance

Creating an RSVP

RSVP as Going

Task { @MainActor in
    do {
        let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
        let rsvp = try await event.createRSVP(status: .going)
        print("RSVP created: \(rsvp.status)")
    } catch {
        print("Failed to RSVP: \(error)")
    }
}

RSVP as Interested

let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
let rsvp = try await event.createRSVP(status: .interested)

RSVP as Not Going

let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
let rsvp = try await event.createRSVP(status: .notGoing)

Updating an RSVP

Change existing RSVP response:
Task { @MainActor in
    do {
        let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
        let updatedRSVP = try await event.updateRSVP(status: .notGoing)
        print("RSVP updated to: \(updatedRSVP.status)")
    } catch {
        print("Failed to update RSVP: \(error)")
    }
}

Getting My RSVP

Check current user’s RSVP status for an event:
Task { @MainActor in
    do {
        let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
        let myRSVP = try await event.getMyRSVP()
        
        if let rsvp = myRSVP {
            print("My RSVP status: \(rsvp.status)")
            print("Responded at: \(rsvp.respondedAt)")
        } else {
            print("No RSVP yet")
        }
    } catch {
        print("Failed to get RSVP: \(error)")
    }
}

Querying Event Attendees

Get All Going Attendees

let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
let attendees = event.getRSVPs(status: .going)

attendees.observe { responses in
    responses.forEach { rsvp in
        print("Attendee: \(rsvp.user.displayName)")
        print("Responded at: \(rsvp.respondedAt)")
    }
    print("Total going: \(responses.count)")
}

Get Interested Users

let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
let interested = event.getRSVPs(status: .interested)

interested.observe { responses in
    print("Interested count: \(responses.count)")
    responses.forEach { rsvp in
        print("- \(rsvp.user.displayName)")
    }
}

Get Not Going Users

let event = try await AmityEventRepository.shared.getEvent(id: "event-123")
let notGoing = event.getRSVPs(status: .notGoing)

notGoing.observe { responses in
    print("Not going count: \(responses.count)")
}

RSVP Data Model

The AmityEventResponse object contains:
interface AmityEventResponse {
  status: AmityEventResponseStatus; // going | interested | not_going
  eventId: string;
  event: AmityEvent; // Linked event object
  userId: string; // User who RSVP'd
  user: AmityUser; // Linked user object
  respondedAt: string; // ISO 8601 timestamp
}

Common Use Cases

Display RSVP Status Button

// Get current user's RSVP and display appropriate button
const event = await eventRepository.getEvent(eventId);
const myRSVP = await event.getMyRSVP();

if (!myRSVP) {
    // Show RSVP options
    displayRSVPOptions();
} else if (myRSVP.status === AmityEventResponseStatus.GOING) {
    // Show "Going" button, allow change
    displayGoingButton(myRSVP);
} else if (myRSVP.status === AmityEventResponseStatus.INTERESTED) {
    // Show "Interested" button, allow change
    displayInterestedButton(myRSVP);
} else {
    // Show "Not Going" button, allow change
    displayNotGoingButton(myRSVP);
}

Attendee List with Real-Time Updates

// Display attendee list that updates in real-time
const event = await eventRepository.getEvent(eventId);
const attendees = event.getRSVPs(AmityEventResponseStatus.GOING);

attendees.on("dataUpdated", (responses) => {
    const attendeeList = responses.map(rsvp => ({
        userId: rsvp.userId,
        name: rsvp.user.displayName,
        avatar: rsvp.user.avatar,
        respondedAt: rsvp.respondedAt
    }));
    
    updateAttendeeUI(attendeeList);
    updateCountBadge(responses.length);
});

RSVP Summary

// Get comprehensive RSVP summary
const event = await eventRepository.getEvent(eventId);

console.log(`RSVP Summary for: ${event.title}`);
console.log(`Going: ${event.rsvpCount}`);
console.log(`Interested: ${event.interestedCount}`);

// Optionally get detailed lists
const going = event.getRSVPs(AmityEventResponseStatus.GOING);
const interested = event.getRSVPs(AmityEventResponseStatus.INTERESTED);

Toggle RSVP Status

// Toggle between Going and Not Going
async function toggleRSVP(eventId: string) {
    const event = await eventRepository.getEvent(eventId);
    const myRSVP = await event.getMyRSVP();
    
    if (!myRSVP || myRSVP.status !== AmityEventResponseStatus.GOING) {
        // Create or update to Going
        if (!myRSVP) {
            await event.createRSVP(AmityEventResponseStatus.GOING);
        } else {
            await event.updateRSVP(AmityEventResponseStatus.GOING);
        }
        showNotification("You're going to this event!");
    } else {
        // Update to Not Going
        await event.updateRSVP(AmityEventResponseStatus.NOT_GOING);
        showNotification("RSVP updated");
    }
}

Best Practices

Maintain UI state based on RSVP status:
// Check RSVP status before showing options
const myRSVP = await event.getMyRSVP();

if (myRSVP) {
    // User has RSVP'd - show update options
    showRSVPUpdateUI(myRSVP.status);
} else {
    // User hasn't RSVP'd - show create options
    showRSVPCreateUI();
}
Subscribe to attendee lists for live updates:
  • Use live collections for attendee lists
  • Update counts automatically
  • Unsubscribe when view is dismissed
  • Handle network disconnections gracefully
Handle RSVP errors appropriately:
try {
    await event.createRSVP(status);
} catch (error) {
    if (error.code === 'ALREADY_EXISTS') {
        // User already RSVP'd, use update instead
        await event.updateRSVP(status);
    } else if (error.code === 'EVENT_ENDED') {
        showError("This event has ended");
    } else {
        showError("Failed to RSVP");
    }
}
Optimize attendee list queries:
  • Implement pagination for large attendee lists
  • Cache frequently viewed lists
  • Load counts separately from full lists
  • Use appropriate query limits

Notifications

RSVP actions may trigger notifications:
ActionNotification Trigger
User RSVPs “Going”Event creator notified of new attendee
User changes to “Not Going”Event creator may be notified
Event updatesAll “Going” attendees notified of changes
Event reminderAll “Going” and “Interested” users notified
Notification Settings: Notification behavior is configurable at the network level through the Admin Console.

Error Handling

do {
    try await event.createRSVP(status: .going)
} catch AmityError.alreadyExists {
    // RSVP already exists, use update instead
    try await event.updateRSVP(status: .going)
} catch AmityError.eventEnded {
    showError("Cannot RSVP to ended event")
} catch AmityError.eventCancelled {
    showError("This event has been cancelled")
} catch {
    showError("Failed to RSVP: \(error.localizedDescription)")
}