Skip to Content
API ReferenceEvents API

Events API

The Events API provides methods for accessing event history, timelines, and audit trails.

Overview

All operations in Synap SDK are event-sourced - every mutation creates an immutable event record. The Events API allows you to:

  • View complete history for any entity
  • Access your entire timeline
  • Replay events to rebuild state
  • Implement audit trails
import { SynapSDK } from '@synap/sdk' const synap = new SynapSDK({ url: 'https://api.synap.app', apiKey: 'your-api-key' }) // Access the Events API synap.events

Methods

getHistory()

Get complete event history for a specific entity.

Signature:

getHistory(entityId: string, options?: EventHistoryOptions): Promise<Event[]>

Parameters:

interface Event HistoryOptions { eventTypes?: string[] // Filter by event type limit?: number // Max results (default: 100) }

Returns:

interface Event { id: string aggregateId: string // Entity ID aggregateType: string // 'entity' | 'relation' eventType: string // e.g. 'entities.create.validated' data: Record<string, unknown> metadata: Record<string, unknown> version: number userId: string createdAt: Date }

Example:

// Get all events for an entity const history = await synap.events.getHistory(entityId) history.forEach(event => { console.log(`${event.createdAt}: ${event.eventType}`) console.log(event.data) }) // Filter by event type const createEvents = await synap.events.getHistory(entityId, { eventTypes: ['entities.create.validated'] }) // Limit results const recent = await synap.events.getHistory(entityId, { limit: 10 })

Event Types:

// Entity events 'entities.create.requested' 'entities.create.validated' 'entities.update.requested' 'entities.update.validated' 'entities.delete.requested' 'entities.delete.validated' // Relation events 'relations.create.requested' 'relations.create.validated' 'relations.delete.requested' 'relations.delete.validated'

Use Cases:

// Audit trail const history = await synap.events.getHistory(taskId) console.log(`Task was modified ${history.length} times`) // Find who created entity const createEvent = history.find(e => e.eventType === 'entities.create.validated' ) console.log(`Created by: ${createEvent.userId}`) // Track all changes const updates = history.filter(e => e.eventType.includes('update') ) console.log(`${updates.length} updates`)

getTimeline()

Get your complete timeline of events.

Signature:

getTimeline(options?: TimelineOptions): Promise<Event[]>

Parameters:

interface TimelineOptions { limit?: number // Max results (default: 50) type?: string // Filter by event type subjectId?: string // Filter by entity subjectType?: string // Filter by aggregate type after?: Date // Events after date before?: Date // Events before date }

Example:

// Get recent activity const timeline = await synap.events.getTimeline({ limit: 20 }) // Filter by date range const lastWeek = await synap.events.getTimeline({ after: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), limit: 100 }) // Filter by event type const creates = await synap.events.getTimeline({ type: 'entities.create.validated', limit: 50 }) // Filter by entity const taskEvents = await synap.events.getTimeline({ subjectId: taskId, limit: 100 })

Activity Dashboard:

// Build activity dashboard const timeline = await synap.events.getTimeline({ limit: 50 }) const stats = { created: timeline.filter(e => e.eventType.includes('create')).length, updated: timeline.filter(e => e.eventType.includes('update')).length, deleted: timeline.filter(e => e.eventType.includes('delete')).length } console.log('Recent activity:', stats)

replay()

Replay events to rebuild entity state.

Signature:

replay(entityId: string): Promise<EntityState>

Returns:

interface EntityState { id: string version: number state: Record<string, unknown> events: Event[] }

Example:

// Rebuild entity state from events const state = await synap.events.replay(entityId) console.log('Current version:', state.version) console.log('State:', state.state) console.log('Event count:', state.events.length)

Time Travel:

// Get state at specific point in time const history = await synap.events.getHistory(entityId) // Filter events up to a date const pastEvents = history.filter(e => e.createdAt <= new Date('2024-12-01') ) // Manually rebuild state let state = {} pastEvents.forEach(event => { if (event.eventType === 'entities.create.validated') { state = event.data } else if (event.eventType === 'entities.update.validated') { state = { ...state, ...event.data } } })

Common Patterns

Activity Feed

// Build activity feed async function getActivityFeed (limit = 20) { const events = await synap.events.getTimeline({ limit }) return events.map(event => ({ timestamp: event.createdAt, action: getActionLabel(event.eventType), data: event.data })) } function getActionLabel(eventType: string) { if (eventType.includes('create')) return 'created' if (eventType.includes('update')) return 'updated' if (eventType.includes('delete')) return 'deleted' return 'modified' } const feed = await getActivityFeed()

Audit Log

// Generate audit log for entity async function generateAuditLog(entityId: string) { const history = await synap.events.getHistory(entityId) return history.map(event => ({ date: event.createdAt.toISOString(), user: event.userId, action: event.eventType, changes: event.data, version: event.version })) } const auditLog = await generateAuditLog(taskId) console.table(auditLog)

Change Detection

// Detect what changed function detectChanges(events: Event[]) { const changes = [] for (let i = 1; i < events.length; i++) { const prev = events[i - 1].data const curr = events[i].data const changedFields = Object.keys(curr).filter(key => JSON.stringify(prev[key]) !== JSON.stringify(curr[key]) ) if (changedFields.length > 0) { changes.push({ timestamp: events[i].createdAt, fields: changedFields }) } } return changes } const history = await synap.events.getHistory(entityId) const changes = detectChanges(history)

Event Notifications

// Poll for new events let lastEventTime = new Date() setInterval(async () => { const newEvents = await synap.events.getTimeline({ after: lastEventTime, limit: 100 }) if (newEvents.length > 0) { handleNewEvents(newEvents) lastEventTime = newEvents[0].createdAt } }, 5000) // Poll every 5 seconds function handleNewEvents(events: Event[]) { events.forEach(event => { console.log('New event:', event.eventType) // Trigger UI update, notification, etc. }) }

Event Structure

Entity Create Event

{ id: "evt_123", aggregateId: "entity_456", aggregateType: "entity", eventType: "entities.create.validated", data: { id: "entity_456", type: "task", title: "Review PR", metadata: { priority: "high" } }, metadata: {}, version: 1, userId: "user_789", createdAt: "2024-12-20T10:30:00Z" }

Entity Update Event

{ id: "evt_124", aggregateId: "entity_456", aggregateType: "entity", eventType: "entities.update.validated", data: { entityId: "entity_456", title: "Review PR #123", metadata: { status: "done" } }, metadata: {}, version: 2, userId: "user_789", createdAt: "2024-12-20T15:00:00Z" }

Relation Create Event

{ id: "evt_125", aggregateId: "rel_999", aggregateType: "relation", eventType: "relations.create.validated", data: { id: "rel_999", sourceEntityId: "task_456", targetEntityId: "person_789", type: "assigned_to" }, metadata: {}, version: 1, userId: "user_789", createdAt: "2024-12-20T15:05:00Z" }

Best Practices

✅ Do’s

// Use for audit trails const history = await synap.events.getHistory(entityId) console.log(`Entity has ${history.length} events`) // Filter to reduce data const recent = await synap.events.getHistory(entityId, { limit: 10 }) // Cache timeline results let timelineCache = await synap.events.getTimeline({ limit: 50 }) // Use for debugging const events = await synap.events.getHistory(entityId) console.log('Event sequence:', events.map(e => e.eventType))

❌ Don’ts

// Don't fetch unlimited events const all = await synap.events.getHistory(entityId) // Use limit! // Don't poll too frequently setInterval(() => { synap.events.getTimeline() // Use SSE or webhooks instead }, 100) // Too frequent! // Don't store full history in memory const massive = await synap.events.getTimeline({ limit: 10000 }) // Too much

Use Cases

1. Audit Trail

Track all changes to sensitive data for compliance.

2. Debugging

Reproduce issues by inspecting event sequence.

3. Analytics

Analyze user behavior from event patterns.

4. Undo/Redo

Implement time travel features in your app.

5. Activity Feed

Show user what’s happening in real-time.

6. Data Recovery

Restore deleted or corrupted entities from events.


Type Safety

Full TypeScript support:

import { Event } from '@synap/sdk' const events: Event[] = await synap.events.getHistory(entityId) events.forEach((event: Event) => { console.log(event.eventType) // Fully typed })

Next Steps

Last updated on