Skip to main content
Version: 2.2.0

API Guide

This guide provides an overview of the MSR (Multi-Session Replay) module's API endpoints. The API is used for managing recorded sessions, querying session metadata, and controlling the replay process.

Authentication

All API endpoints require a valid JWT access token from IAMs. The token must be included in the Authorization header of each request.

Headers:

  • Content-Type: application/json
  • Authorization: Bearer {token}

Session API


1. Create a session

POST /session

Request

No request body.

Response

NameTypeDescription
iduuidThe ID of the session
user_iduuidThe user_id that session belongs to
tenant_iduuidThe tenant_id that session belongs to
created_atstringThe timestamp in RFC3339 format
update_atstringThe timestamp in RFC3339 format
created_byuuidThe ID of the user who created the session
updated_byuuidThe ID of the user who updated the session
statusstringThe status of the session: ACTIVE, INACTIVE
occ_locknumberThe occ lock of the session
{
"data": {
"id": "4a966973-2131-4521-be48-e3d79306a847",
"user_id": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"tenant_id": "2878ac59-ad8b-4a94-bd97-2d9ef371fc06",
"created_at": "2025-08-05T17:13:24+07:00",
"update_at": "2025-08-05T17:19:05+07:00",
"created_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"updated_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"status": "ACTIVE",
"occ_lock": 0
},
"message": "Created session successfully",
"sent_at": "2025-08-05T10:19:05Z"
}

2. Get initial state

  • Return the state of the session at the given timestamp. If the timestamp is not provided, return the current state of the session.
  • Returns the full, reconstructed state of all entities at a specific point in time.
GET /replay/state?timestamp={timestamp}

Optional query parameters for filtering:

  • filter_tables — comma-separated list of tables to filter (e.g., patients,medications)
  • filter_min_timestamp — ISO timestamp; events older than this are excluded for the specified tables

Example:

GET /replay/state?timestamp=2024-06-15T10:00:00Z&filter_tables=patients,medications&filter_min_timestamp=2024-06-08T10:00:00Z
Timestamp Validation

The requested timestamp must be within the available data range. If the timestamp is:

  • Too early: Returns an error with the earliest available timestamp based on EARLIEST_VALID_TIMESTAMP or snapshot cutoff
  • In the future: Returns an error indicating future timestamps are not supported
  • Outside MAX_PLAYBACK_RANGE: Returns an error with the configured playback limit (default: 7 days)

Response

NameTypeDescription
entity_idstringThe unique id of the entity
entity_stateJSONBThe state of the entity
opstringThe operation: c, r, u, d
event_timestampstringThe timestamp in RFC3339 format
{
"data": [
{
"entity_id": "655e82ca-678c-47f5-8d81-5091c39f8d63",
"entity_state": {
"id": "611f2472-d781-4870-b5fc-69b90bafc067",
"geojson": "{\"type\": \"Feature\", \"geometry\": {\"type\": \"Polygon\", \"coordinates\": [[[103.8493269960454, 1.391235132350934], [103.8493269960454, 1.391235132350934]]]}, \"properties\": {\"kind\": \"task\", \"name\": \"ST Engineering\"}}",
"occ_lock": 0,
"tenant_id": "2878ac59-ad8b-4a94-bd97-2d9ef371fc06",
"created_at": "2025-06-09T03:58:14.762000Z",
"created_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"updated_at": "2025-06-09T03:58:14.762000Z",
"updated_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"entity_type": "static"
},
"op": "r",
"event_timestamp": "2025-08-01T14:15:14+07:00"
},
{
"entity_id": "8fbeedce-cbca-4aee-a01f-0ee23b583797",
"entity_state": {
"id": "e10e029a-6971-41af-9791-0378fe6f699b",
"geojson": "{\"type\": \"Feature\", \"geometry\": {\"type\": \"Point\", \"coordinates\": [103.8493269960454, 1.391235132350934]}, \"properties\": {\"kind\": \"task\", \"name\": \"ST Engineering\"}}",
"occ_lock": 0,
"tenant_id": "2878ac59-ad8b-4a94-bd97-2d9ef371fc06",
"created_at": "2025-06-09T04:00:31.229000Z",
"created_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"updated_at": "2025-06-09T04:00:31.229000Z",
"updated_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"entity_type": "static"
},
"op": "r",
"event_timestamp": "2025-08-01T14:15:14+07:00"
}
],
"message": "Get initial state successfully",
"sent_at": "2025-08-07T02:25:38Z"
}

3. Get transaction logs

  • Returns the transaction logs between the start and end timestamps.
GET /replay/events?start={timestamp}&end={timestamp}

Optional query parameters for filtering:

  • filter_tables — comma-separated list of tables to filter (e.g., audit_logs,activity_logs)
  • filter_min_timestamp — ISO timestamp; events older than this are excluded for the specified tables

Example:

GET /replay/events?start=2024-06-15T10:00:00Z&end=2024-06-15T12:00:00Z&filter_tables=audit_logs,activity_logs&filter_min_timestamp=2024-06-14T10:00:00Z

Response

NameTypeDescription
entity_idstringThe unique id of the entity
entity_stateJSONBThe state of the entity
opstringThe operation: c, r, u, d
event_timestampstringThe timestamp in RFC3339 format
{
"data": [
{
"entity_id": "655e82ca-678c-47f5-8d81-5091c39f8d63",
"entity_state": {
"id": "611f2472-d781-4870-b5fc-69b90bafc067",
"geojson": "{\"type\": \"Feature\", \"geometry\": {\"type\": \"Polygon\", \"coordinates\": [[[103.8493269960454, 1.391235132350934], [103.8493269960454, 1.391235132350934]]]}, \"properties\": {\"kind\": \"task\", \"name\": \"ST Engineering\"}}",
"occ_lock": 0,
"tenant_id": "2878ac59-ad8b-4a94-bd97-2d9ef371fc06",
"created_at": "2025-06-09T03:58:14.762000Z",
"created_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"updated_at": "2025-06-09T03:58:14.762000Z",
"updated_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"entity_type": "static"
},
"op": "r",
"event_timestamp": "2025-08-01T14:15:14+07:00"
},
{
"entity_id": "8fbeedce-cbca-4aee-a01f-0ee23b583797",
"entity_state": {
"id": "e10e029a-6971-41af-9791-0378fe6f699b",
"geojson": "{\"type\": \"Feature\", \"geometry\": {\"type\": \"Point\", \"coordinates\": [103.8493269960454, 1.391235132350934]}, \"properties\": {\"kind\": \"task\", \"name\": \"ST Engineering\"}}",
"occ_lock": 0,
"tenant_id": "2878ac59-ad8b-4a94-bd97-2d9ef371fc06",
"created_at": "2025-06-09T04:00:31.229000Z",
"created_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"updated_at": "2025-06-09T04:00:31.229000Z",
"updated_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"entity_type": "static"
},
"op": "r",
"event_timestamp": "2025-08-01T14:15:14+07:00"
}
],
"message": "Successfully retrieved transaction logs.",
"sent_at": "2025-08-07T02:25:38Z"
}


4. Delete a session

DELETE /session/{id}

Request

ParameterTypeDescription
iduuidThe unique identifier of the session to delete (path parameter)

Response

HTTP status code 204 with message "Deleted session successfully".


5. Terminate a session

POST /session/{session_id}/terminate
Authorization

This endpoint only allows users to terminate sessions they own. To terminate sessions for other users, use the admin endpoint POST /admin/sessions/terminate.

Response

HTTP status code 204.


6. Admin terminate multiple sessions

POST /admin/sessions/terminate
Admin Authorization

This admin endpoint allows terminating sessions for any user. For terminating your own sessions, you can use the user endpoint POST /session/{session_id}/terminate.

Request Body

NameTypeDescription
session_idsarrayArray of session IDs (UUIDs) to terminate
{
"session_ids": ["468a27ed-f6d9-4c7c-8772-0dafd4e79ac3", "8766a359-17a4-4dbe-b6e4-d0e73eabadc7"]
}

Admin API


7. Get sessions configuration

  • Returns the session configuration: max_active_sessions, max_playback_range, data_retention_cron_expression, earliest_valid_timestamp
GET /admin/settings

Response

NameTypeDescription
max_active_sessionsnumberThe maximum number of active sessions that can be created
max_playback_rangenumberThe maximum historical range allowed for playback (unit: day(s))
data_retention_cron_expressionstringCron expression for data retention cleanup schedule (standard cron format)
earliest_valid_timestampstringSystem deployment boundary timestamp in ISO 8601 format with timezone
query_work_mem_mbnumberQuery work memory allocation in MB for database operations
columnstore_compression_age_daysnumberAge in days after which columnstore data gets compressed
cagg_refresh_interval_hoursnumberContinuous aggregate refresh interval in hours
cagg_refresh_lag_daysnumberContinuous aggregate refresh lag in days
{
"data": {
"max_active_sessions": 10,
"max_playback_range": 30,
"data_retention_cron_expression": "0 2 * * *",
"earliest_valid_timestamp": "2024-01-15T00:00:00Z",
"query_work_mem_mb": 256,
"columnstore_compression_age_days": 7,
"cagg_refresh_interval_hours": 1,
"cagg_refresh_lag_days": 1
},
"sent_at": "2025-08-05T10:19:05Z"
}

8. Update configuration

  • Update the runtime configuration for the service.
PUT /admin/settings

Request

NameTypeDescription
max_active_sessionsnumberThe maximum number of active sessions that can be created (must be > 0)
max_playback_rangenumberThe maximum historical range allowed for playback in days (must be > 0)
data_retention_cron_expressionstringCron expression for data retention cleanup schedule (standard cron format)
earliest_valid_timestampstringSystem deployment boundary timestamp in ISO 8601 format with timezone (YYYY-MM-DDTHH:MM:SSZ)
query_work_mem_mbnumberQuery work memory allocation in MB for database operations (must be > 0)
columnstore_compression_age_daysnumberAge in days after which columnstore data gets compressed (must be > 0)
cagg_refresh_interval_hoursnumberContinuous aggregate refresh interval in hours (must be > 0)
cagg_refresh_lag_daysnumberContinuous aggregate refresh lag in days (must be > 0)
{
"max_active_sessions": 15,
"max_playback_range": 45,
"data_retention_cron_expression": "0 2 * * *",
"earliest_valid_timestamp": "2024-01-15T00:00:00Z",
"query_work_mem_mb": 512,
"columnstore_compression_age_days": 14,
"cagg_refresh_interval_hours": 2,
"cagg_refresh_lag_days": 2
}

Response

Returns the updated configuration values that were provided in the request.

{
"data": {
"max_active_sessions": 15,
"max_playback_range": 45,
"data_retention_cron_expression": "0 2 * * *",
"earliest_valid_timestamp": "2024-01-15T00:00:00Z",
"query_work_mem_mb": 512,
"columnstore_compression_age_days": 14,
"cagg_refresh_interval_hours": 2,
"cagg_refresh_lag_days": 2
},
"sent_at": "2025-09-04T10:19:05Z"
}

9. List sessions

GET /admin/sessions

Query params

NameTypeDescription
tenant_idstringThe tenant id to filter session that belongs to tenant
statusstringThe status to filter sessions (ACTIVE, INACTIVE)
pagenumberPagination page
sizenumberPagination size
sortnumberCondition for sorting the sessions data

Response

NameTypeDescription
iduuidThe unique id of the session
user_iduuidThe user id that session belongs to
statusstringThe session status: ACTIVE, INACTIVE
last_seen_atstringThe timestamp of the last API call using this session
tenant_idstringThe tenant id that session belongs to
occ_lockstringThe a mutex for optimistic concurrency control
created_atstringThe time this session was created
updated_atstringThe time this session was last updated
numberintThe page from request
sizeintThe size from request
total_recordsintThe total records that match request query
countintThe number of sessions in the current page
sortstringThe sort column and direction
{
"data": [
{
"id": "468a27ed-f6d9-4c7c-8772-0dafd4e79ac3",
"user_id": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"status": "INACTIVE",
"last_seen_at": "2025-08-11T14:48:12+07:00",
"tenant_id": "6c17fb87-d715-439f-943f-69f01318adac",
"occ_lock": 2,
"created_at": "2025-08-11T14:47:38+07:00",
"update_at": "2025-08-11T14:48:12+07:00",
"created_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"updated_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0"
},
{
"id": "8766a359-17a4-4dbe-b6e4-d0e73eabadc7",
"user_id": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db1",
"status": "ACTIVE",
"last_seen_at": "2025-08-11T14:43:48+07:00",
"tenant_id": "6c17fb87-d715-439f-943f-69f01318adac",
"occ_lock": 1,
"created_at": "2025-08-11T14:43:48+07:00",
"update_at": "2025-08-11T14:46:55+07:00",
"created_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0",
"updated_by": "f67cb8f5-0645-444d-a4bd-c61aaf1b2db0"
}
],
"message": "Retrieved list sessions successfully",
"sent_at": "2025-08-12T02:53:24Z",
"page": {
"number": 1,
"size": 2,
"total_records": 7,
"count": 2,
"sort": ["last_seen_at,desc"]
}
}

10. Get active sessions count

GET /admin/sessions/status

Response

NameTypeDescription
active_sessionsnumberThe count of currently active sessions
{
"data": {
"active_sessions": 3
},
"sent_at": "2025-09-09T10:19:05Z"
}

Performance Tuning Configuration

The MSR service supports additional performance tuning configuration parameters through the Admin API endpoints (GET/PUT /admin/settings). These parameters allow fine-tuning of database performance and data management operations.

Available Performance Parameters

ParameterTypeDescriptionUse Case
query_work_mem_mbnumberMemory allocation in MB for database query operationsHigher values improve performance for complex queries but consume more memory
columnstore_compression_age_daysnumberAge threshold in days after which columnstore data undergoes compressionShorter periods save storage space but may impact write performance
cagg_refresh_interval_hoursnumberRefresh interval in hours for continuous aggregatesMore frequent refreshes provide up-to-date aggregate data but increase system load
cagg_refresh_lag_daysnumberLag time in days for continuous aggregate refresh operationsPrevents refreshing recent data that might still be changing

Configuration Guidelines

Query Work Memory (query_work_mem_mb)

  • Default: Varies by deployment
  • Range: 64MB - 2048MB recommended
  • Impact: Higher values improve sort and hash operations but increase memory usage per connection
  • Recommendation: Start with 256MB, increase for heavy analytical workloads

Columnstore Compression (columnstore_compression_age_days)

  • Default: 7 days
  • Range: 1-30 days recommended
  • Impact: Shorter periods reduce storage costs but increase background compression activity
  • Recommendation: 7-14 days for most workloads

Continuous Aggregate Refresh (cagg_refresh_interval_hours)

  • Default: 1 hour
  • Range: 0.25-24 hours
  • Impact: More frequent refreshes provide fresher data but consume more CPU/IO
  • Recommendation: 1-4 hours depending on data freshness requirements

Refresh Lag (cagg_refresh_lag_days)

  • Default: 1 day
  • Range: 0-7 days
  • Impact: Longer lag prevents refreshing unstable recent data
  • Recommendation: 1-2 days for stable performance

Example Configuration

{
"query_work_mem_mb": 512,
"columnstore_compression_age_days": 10,
"cagg_refresh_interval_hours": 2,
"cagg_refresh_lag_days": 1
}
Performance Monitoring

After adjusting these parameters, monitor system metrics:

  • Memory usage per connection
  • Storage compression ratios
  • Aggregate refresh execution times
  • Query performance metrics

Health Check API


11. Readiness Check

GET /readiness

Description

Checks if the service is ready to handle requests. This endpoint verifies database connectivity.

Response

  • 200 OK: Service is ready
  • 503 Service Unavailable: Service is not ready (e.g., database connection failed)

12. Liveness Check

GET /health

Description

Checks if the service is alive and running. This endpoint verifies basic service health including database connectivity.

Response

  • 200 OK: Service is alive
  • 503 Service Unavailable: Service is not healthy

Frontend API Client

The MSR modlet includes a comprehensive TypeScript API client for interacting with backend services. The client provides:

  • Error handling: Automatic error interception with user-friendly toast notifications
  • Type safety: Full TypeScript types for requests and responses
  • Correlation IDs: Support tracking for debugging and support
  • Custom error handlers: Override default behavior with custom logic

Client Functions

Session Management

import {
createSession,
terminateSession,
getPlaybackRange,
getInitialState,
getReplayEvents,
} from "$lib/aoh/msr/api/client";

// Create a new replay session
const { sessionId } = await createSession();

// Terminate a session
await terminateSession(sessionId);

Playback Data

// Get playback range configuration
const range: PlaybackRange = await getPlaybackRange();
// Returns: { maxDays: 7, startDate: "2024-01-01T00:00:00", endDate: "2024-01-08T00:00:00", earliestValidDate?: "2024-01-01T00:00:00" }

// Get initial state at timestamp
const timestamp = new Date("2024-01-05T12:00:00Z");
const events: ReplayEvent[] = await getInitialState(timestamp);

// Get events between timestamps
const startTime = new Date("2024-01-05T12:00:00Z");
const endTime = new Date("2024-01-05T13:00:00Z");
const changeEvents: ReplayEvent[] = await getReplayEvents(startTime, endTime);

Error Handling System

The API client includes a comprehensive error handling system with:

Structured Error Format:

interface MsrError {
code: string; // Error code (e.g., "SESSION_LIMIT_REACHED")
message: string; // User-friendly error message
correlationId: string; // Unique ID for support tracking
isRetryable: boolean; // Whether operation can be retried
action?: string; // Suggested action (e.g., "terminate_existing_session")
details?: Record<string, unknown>; // Additional error context
}

Default Error Handling:

By default, errors are displayed using Sonner toast notifications with correlation IDs:

// Automatic error handling with toast
try {
const { sessionId } = await createSession();
} catch (error) {
// Error is already displayed to user via toast
// Correlation ID included for support
}

Custom Error Handling:

import { configureMsrErrorHandling } from "$lib/aoh/msr/api/client";

// Configure custom error handling
configureMsrErrorHandling({
onError: async (error, context, options) => {
// Send to custom error tracking
await sendToSentry({
errorCode: error.code,
correlationId: error.correlationId,
operation: context.operation,
timestamp: context.timestamp,
});

// Show custom UI
if (error.code === "SESSION_LIMIT_REACHED") {
showCustomSessionLimitModal();
}
},
defaultOptions: {
showToast: true, // Still show default toasts
logError: true, // Log to console
throwError: false, // Don't re-throw
},
});

Error Context:

interface ErrorContext {
operation: string; // Operation that failed (e.g., "create_session")
timestamp: Date; // When error occurred
sessionId?: string; // Session ID if applicable
component: string; // Component that initiated request
}

Type Definitions

Key types for API responses:

// Playback range configuration
interface PlaybackRange {
maxDays: number; // MAX_PLAYBACK_RANGE value
startDate: string; // Earliest selectable date (ISO format)
endDate: string; // Latest selectable date (ISO format)
earliestValidDate?: string; // EARLIEST_VALID_TIMESTAMP if configured
}

// Replay event
interface ReplayEvent {
entityId: string;
entityState: EntityState | null; // Null for delete operations
operation: "create" | "read" | "update" | "delete";
timestamp: Date;
tableName: string;
}

// Entity state (generic)
type EntityState<T = JSONValue> = T;

// Change event (backend format)
interface ChangeEvent {
entity_id: string;
op: "c" | "r" | "u" | "d";
entity_state: EntityState | null;
event_timestamp: string;
table_name: string;
}

Common Error Codes

Error CodeDescriptionRetryableSuggested Action
SESSION_LIMIT_REACHEDMaximum concurrent sessions exceededNoTerminate existing session
SESSION_CREATION_FAILEDFailed to create session (backend issue)YesRetry after a moment
NETWORK_ERRORNetwork connectivity problemYesCheck connection and retry
INTERNAL_SERVER_ERRORUnexpected backend errorNoContact support with correlation ID
TIMESTAMP_OUT_OF_RANGERequested timestamp outside available data rangeNoSelect different timestamp
INVALID_PLAYBACK_WINDOWPlayback window exceeds configured limitsNoReduce playback window duration
UNAUTHORIZEDInvalid or expired authentication tokenNoRe-authenticate

Best Practices

1. Let the client handle errors by default:

// ✅ Simple - errors shown automatically
const { sessionId } = await createSession();

// ❌ Unnecessary - already handled
try {
const { sessionId } = await createSession();
} catch (error) {
alert("Error creating session"); // Duplicates toast
}

2. Provide correlation IDs to users when needed:

// Errors already include correlation IDs in toast messages
// Users can reference these when contacting support

3. Use custom handlers for application-specific logic:

// ✅ Add custom behavior while keeping default toasts
configureMsrErrorHandling({
onError: async (error, context) => {
// Track in analytics
trackEvent("msr_error", {
errorCode: error.code,
operation: context.operation,
});

// Redirect on specific errors
if (error.code === "UNAUTHORIZED") {
window.location.href = "/login";
}
},
defaultOptions: {
showToast: true, // Keep showing toasts
logError: true,
},
});

4. Handle expected errors gracefully:

// For operations where errors are expected
try {
const range = await getPlaybackRange();
} catch (error) {
// Error already shown to user, provide fallback
const range = {
maxDays: 30,
startDate: dayjs().subtract(30, "day").format(),
endDate: dayjs().format(),
};
}