Skip to main content
User events are published when users are mentioned in comments or when user-related activities occur. These events enable real-time notification systems and user engagement tracking. These events are delivered through the platform events system.

Developer quickstart

Minimal handler (mentions only)

app.post("/webhook/platform-events", async (req, res) => {
  const event = req.body;
  if (!event?.eventId || event?.eventType !== "user:mentioned") {
    return res.status(200).send("OK");
  }
  res.status(200).send("OK");

  await onUserMentioned(event.payload.user, event.metadata);
});

Checklist

  • Respect user notification preferences and quiet hours when sending alerts.
  • Enrich notifications with context (linked entity, comment excerpt) for UX.
  • De-duplicate multiple mentions in the same comment before notifying.

Event types

user:mentioned

Triggered when a user is mentioned in a comment across any entity type (tickets, account tasks, activities, or notes). Payload structure:
interface UserMentionEventPayload {
  user: {
    id: string;
    email: string;
    name: string;
    userType: string;
    status: string;
    organization: {
      id: string;
      name: string | null;
    };
    teams: Array<{
      id: string;
      name: string;
    }>;
    metadata?: Record<string, unknown>;
  };
}
Event metadata:
interface MentionMetadata {
  mentionedUserId: string;
  mentionedByUserId: string;
  entityId: string;
  entityType: string; // "TICKET", "ACCOUNT_TASK", "ACCOUNT_ACTIVITY", "ACCOUNT_NOTE"
  commentId: string;
  timestamp: string;
  organizationId: string;
  teamId?: string; // Present for ticket mentions
}

Event structure

User events follow the standard platform event structure:
interface UserEventEnvelope {
  eventId: string;
  eventType: string; // "user:mentioned"
  timestamp: string;
  orgId: string;
  actor: {
    id: string;
    type: string;
    email: string;
  };
  payload: UserMentionEventPayload;
  metadata: MentionMetadata;
}

Mention context

Entity types

Users can be mentioned in comments on different entity types:

Ticket mentions

  • Entity type: TICKET
  • Additional context: teamId is included in metadata
  • Common use cases: Agent collaboration, customer escalation, knowledge sharing

Account task mentions

  • Entity type: ACCOUNT_TASK
  • Context: Task collaboration and assignment discussions
  • Common use cases: Task handoffs, status updates, collaboration requests

Account activity mentions

  • Entity type: ACCOUNT_ACTIVITY
  • Context: Activity discussions and follow-ups
  • Common use cases: Activity reviews, next steps planning

Account note mentions

  • Entity type: ACCOUNT_NOTE
  • Context: Note discussions and clarifications
  • Common use cases: Knowledge sharing, note reviews, clarifications

Event processing

Mention detection

The system automatically detects mentions in comment content using patterns like:
  • @username
  • @user.email
  • @"Full Name"

Deduplication

Multiple users can be mentioned in a single comment, generating separate events for each mentioned user.

Self-mention filtering

Users mentioning themselves may be filtered out based on the ignoreSelf flag in the comment metadata.

Integration examples

Real-time notification system

function handleUserMention(payload) {
  const { user, metadata } = payload;

  // Get mention context
  const context = getMentionContext(metadata.entityType, metadata.entityId);

  // Create notification
  const notification = {
    userId: user.id,
    type: 'mention',
    title: `You were mentioned by ${payload.actor.name}`,
    message: createMentionMessage(context, payload.actor),
    actionUrl: generateActionUrl(metadata),
    createdAt: new Date(payload.timestamp)
  };

  // Send real-time notification
  sendRealtimeNotification(user.id, notification);

  // Send email if user preferences allow
  if (await shouldSendEmailNotification(user.id, 'mention')) {
    sendMentionEmail(user, notification, context);
  }

  // Send mobile push notification
  if (await shouldSendPushNotification(user.id, 'mention')) {
    sendPushNotification(user.id, notification);
  }
}

Mention analytics

function trackMentionMetrics(payload) {
  const { metadata } = payload;

  // Track mention frequency
  trackEvent("user_mentioned", {
    mentionedUserId: metadata.mentionedUserId,
    mentionedByUserId: metadata.mentionedByUserId,
    entityType: metadata.entityType,
    organizationId: metadata.organizationId,
    teamId: metadata.teamId,
    timestamp: metadata.timestamp,
  });

  // Update user engagement scores
  updateUserEngagement(metadata.mentionedUserId, {
    type: "mention_received",
    weight: 1,
  });

  updateUserEngagement(metadata.mentionedByUserId, {
    type: "mention_sent",
    weight: 0.5,
  });

  // Track cross-team collaboration
  if (metadata.teamId) {
    trackCrossTeamCollaboration(
      metadata.mentionedByUserId,
      metadata.mentionedUserId,
      metadata.teamId,
    );
  }
}

Smart notification routing

function routeMentionNotification(payload) {
  const { user, metadata } = payload;

  // Check user availability
  const availability = await getUserAvailability(user.id);

  if (!availability.isAvailable) {
    // User is out of office or busy
    if (metadata.entityType === 'TICKET' && isPriorityTicket(metadata.entityId)) {
      // Route to team lead for high-priority tickets
      const teamLead = await getTeamLead(metadata.teamId);
      notifyTeamLead(teamLead, payload, 'user_unavailable');
    } else {
      // Queue notification for later
      queueNotificationForLater(user.id, payload, availability.returnTime);
    }
  } else {
    // User is available, send normal notification
    sendImmediateNotification(user.id, payload);
  }
}

Mention context enhancement

function enhanceMentionContext(payload) {
  const { metadata } = payload;

  // Get rich context based on entity type
  let context = {};

  switch (metadata.entityType) {
    case 'TICKET':
      context = await getTicketContext(metadata.entityId);
      break;
    case 'ACCOUNT_TASK':
      context = await getAccountTaskContext(metadata.entityId);
      break;
    case 'ACCOUNT_ACTIVITY':
      context = await getAccountActivityContext(metadata.entityId);
      break;
    case 'ACCOUNT_NOTE':
      context = await getAccountNoteContext(metadata.entityId);
      break;
  }

  // Get comment context
  const comment = await getComment(metadata.commentId);

  // Create enhanced notification
  const enhancedPayload = {
    ...payload,
    context: {
      entity: context,
      comment: {
        id: comment.id,
        excerpt: truncateText(comment.content, 100),
        author: comment.author
      },
      urgency: calculateUrgency(context, comment),
      suggestedActions: generateSuggestedActions(context, comment)
    }
  };

  return enhancedPayload;
}

User preference management

function handleMentionWithPreferences(payload) {
  const { user } = payload;

  // Get user notification preferences
  const preferences = await getUserNotificationPreferences(user.id);

  // Check if mentions are enabled
  if (!preferences.mentions.enabled) {
    logSkippedNotification(user.id, 'mentions_disabled');
    return;
  }

  // Check time-based preferences
  if (preferences.mentions.quietHours) {
    const now = new Date();
    const userTimezone = user.timezone || 'UTC';

    if (isInQuietHours(now, preferences.mentions.quietHours, userTimezone)) {
      queueNotificationForLater(user.id, payload,
        getNextActiveTime(preferences.mentions.quietHours, userTimezone));
      return;
    }
  }

  // Check entity-specific preferences
  const entityPrefs = preferences.mentions.entityTypes[payload.metadata.entityType];
  if (!entityPrefs?.enabled) {
    logSkippedNotification(user.id, `mentions_disabled_for_${payload.metadata.entityType}`);
    return;
  }

  // Process mention with user preferences applied
  processMentionWithPreferences(payload, preferences);
}

Mention patterns and best practices

Mention syntax support

The platform supports various mention formats:
// Standard username mention
@john.smith

// Email-based mention
@john.smith@company.com

// Display name mention (with quotes for spaces)
@"John Smith"

// Department/role mention (if supported)
@support-team

Integration best practices

  1. Deduplication: Handle duplicate mentions gracefully
  2. Rate limiting: Implement rate limiting for mention notifications
  3. Context preservation: Maintain mention context for better user experience
  4. Privacy: Respect user privacy settings and availability status
  5. Fallback handling: Handle cases where mentioned users don’t exist

Performance considerations

function optimizeMentionProcessing(payload) {
  // Batch process multiple mentions from same comment
  const mentionBatch = groupMentionsByComment(payload.metadata.commentId);

  // Pre-load user data for all mentions
  const userIds = mentionBatch.map(m => m.mentionedUserId);
  const users = await batchLoadUsers(userIds);

  // Pre-load preferences
  const preferences = await batchLoadPreferences(userIds);

  // Process all mentions with cached data
  mentionBatch.forEach(mention => {
    processMentionWithCache(mention, users, preferences);
  });
}

Error handling

Common error scenarios

function handleMentionErrors(payload, error) {
  switch (error.type) {
    case "USER_NOT_FOUND":
      // Mentioned user doesn't exist
      logInvalidMention(payload.metadata);
      notifyCommentAuthor("invalid_mention", payload.metadata);
      break;

    case "USER_DEACTIVATED":
      // Mentioned user is deactivated
      logDeactivatedUserMention(payload.metadata);
      // Don't send notification
      break;

    case "NOTIFICATION_SERVICE_DOWN":
      // Notification service unavailable
      queueMentionForRetry(payload);
      break;

    case "RATE_LIMIT_EXCEEDED":
      // Too many notifications for user
      queueMentionForLater(payload);
      break;

    default:
      logMentionError(payload, error);
      alertDevelopmentTeam("mention_processing_error", { payload, error });
  }
}

Event frequency and scaling

Frequency characteristics

User mention events can vary greatly in frequency:
  • Low-volume organizations: Few mentions per day
  • High-collaboration teams: Hundreds of mentions per hour
  • Customer support teams: Spike during business hours

Scaling considerations

  1. Batch processing: Group mentions for efficient processing
  2. Async processing: Handle mention notifications asynchronously
  3. Caching: Cache user data and preferences for better performance
  4. Rate limiting: Prevent notification spam
  5. Monitoring: Track mention processing latency and success rates

Future enhancements

Potential future enhancements to user events:
  • Smart mentions: AI-suggested mentions based on context
  • Group mentions: Mention entire teams or roles
  • Mention threads: Track mention conversation threads
  • Mention analytics: Advanced analytics for collaboration patterns
  • Custom mention actions: Configurable actions when mentioned
I