Search events
Request description
Endpoint: /events/search
Method: POST
Returns the events of an organization within a time range. Results are paginated: there is no maximum number of events per search, you read them page by page until the response says there are no more. This makes the endpoint suitable for exporting events to your own analytics tools (Power BI, Mixpanel, a data warehouse...).
Header
{
"Content-Type": "application/json",
"Authorization": "Bearer <accessToken>"
}
Note: the <accessToken> is obtained as a result of the authentication
Payload
interface ISearchEventPayload {
startTimestamp: number;
endTimestamp: number;
organizationId?: string;
userId?: string;
eventName?: string | string[];
eventType?: EventType | EventType[];
pageSize?: number;
cursor?: string;
outputFormat?: "json" | "csv";
limit?: number; // Deprecated: use pageSize
}
type EventType = "INFO" | "WARNING" | "ERROR";
where:
startTimestamp: Start time (Unix time in milliseconds)endTimestamp: End time (Unix time in milliseconds). Must be greater than or equal tostartTimestamporganizationId(optional): organization whose events are returned. By default, the organization selected in your session. You can search any organization in which you have the Organization Owner or Organization Admin roleuserId(optional): return only the events of this user. Get it from Users list. When omitted, the events of every user in the organization are returnedeventName(optional): return only events with this name, e.g."Complete medical consultation". Send an array (up to 50 values) to match any of several nameseventType(optional): return only events of this type ("INFO","WARNING"or"ERROR"). Send an array to match several typespageSize(optional): number of events per page. Integer between 1 and 5000. 500 by defaultcursor(optional): thepagination.nextCursorvalue of the previous response. Omit it to get the first pageoutputFormat(optional): Output format. (JSON by default)limit(deprecated): previous name ofpageSize, still accepted with the same range. If both are sent,pageSizeis used
Numbers must be sent as numbers, not as strings. Events are returned from the most recent to the oldest.
Pagination
- Send the first request without
cursor. - Read
pagination.hasMorein the response. When it istrue, send the same request again addingcursorwith the value ofpagination.nextCursor. - Repeat until
pagination.hasMoreisfalse(nextCursoris thennull).
504 response, retry
the same page or split the search into shorter time ranges (for example, one day per search).// Example: read every event of yesterday
let cursor: string | undefined;
const events = [];
do {
const response = await fetch(`${BASE_URL}/events/search`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${accessToken}` },
body: JSON.stringify({ startTimestamp, endTimestamp, pageSize: 5000, cursor }),
});
const { events: page, pagination } = await response.json();
events.push(...page);
cursor = pagination.nextCursor ?? undefined;
} while (cursor);
Payload example
{
"startTimestamp": 1788281445980,
"endTimestamp": 1790873445980,
"eventName": ["Start medical report generation", "Complete medical consultation"],
"pageSize": 1000,
"outputFormat": "json"
}
Responses
Correct response
Successful request
Describe the characteristics of a satisfactory response
200
Response structure:
type SearchEventsResponseType = {
events: IEvent[] | string; // IEvent[] for "json", a CSV string for "csv"
pagination: {
pageSize: number; // Page size applied to this search
count: number; // Number of events in this page
hasMore: boolean; // false when there are no more events to return
nextCursor: string | null; // Send it as "cursor" to get the next page. null when hasMore is false
};
};
interface IEvent {
timestamp: string; // Event date in UTC, format "YYYY-MM-DD HH:mm:ss.SSS" (not ISO 8601)
eventName: string; // Event name, e.g. "Start medical report generation"
userId: string;
organizationId: string;
eventType: string; // "INFO", "WARNING" or "ERROR"
section: string; // Area of the platform where the event happened
resource: string; // Related resource, empty when not applicable
metadata?: Record<string, unknown>; // Additional event-specific data. Only present when the event has it
}
outputFormat: "json"):{
"events": [
{
"timestamp": "2026-10-01 14:30:04.741",
"eventName": "Complete medical consultation",
"userId": "mock-user-id",
"organizationId": "mock-organization-id",
"eventType": "INFO",
"section": "genesis",
"resource": ""
}
],
"pagination": {
"pageSize": 1000,
"count": 1,
"hasMore": false,
"nextCursor": null
}
}
outputFormat: "csv"):The response is still a JSON object. The CSV of the page, including its header row, is returned as a string in events. Values containing commas, quotes or line breaks are quoted, and metadata is serialized as JSON:{
"events": "timestamp,eventName,userId,organizationId,eventType,section,resource,metadata\n2026-10-01 14:30:04.741,Complete medical consultation,mock-user-id,mock-organization-id,INFO,genesis,,",
"pagination": {
"pageSize": 500,
"count": 1,
"hasMore": false,
"nextCursor": null
}
}
events is an empty array (or a CSV with only the header row) and pagination.hasMore is false.Wrong responses
Unauthorized request
Describe the characteristics of an unauthorized request
401
Response body
{
"message": "Unauthorized"
}
Description: this error occurs when endpoint authorizers fail to validate the token sent in the request header.
Forbidden request
Describe the characteristics of an forbidden request
403
Response body
{
"message": "Forbidden"
}
Description: this error occurs when your accessToken does not have permission to search for events of the organization: the user does not have the Organization Owner or Organization Admin role in the selected organization or, when organizationId is sent, in that organization.
Bad request
Describe the characteristics of a bad request
400
Response body
type SearchEventErrorResponseType = {
errorType: SEARCH_EVENT_ERROR_TYPE;
errorMessage: string;
};
enum SEARCH_EVENT_ERROR_TYPE {
INVALID_START_TIMESTAMP = "invalidStartTimestamp", // startTimestamp missing or not a number
INVALID_END_TIMESTAMP = "invalidEndTimestamp", // endTimestamp missing or not a number
INVALID_TIMESTAMP_RANGE = "invalidTimestampRange", // startTimestamp is greater than endTimestamp
INVALID_PAGE_SIZE = "invalidPageSize", // pageSize is not an integer between 1 and 5000
INVALID_LIMIT = "invalidLimitValue", // limit is not an integer between 1 and 5000
INVALID_CURSOR = "invalidCursor", // cursor is not a value returned by this endpoint
INVALID_USER_ID = "invalidUserId", // userId is not a valid identifier
INVALID_ORGANIZATION_ID = "invalidOrganizationId", // organizationId is not a valid identifier
INVALID_EVENT_NAME = "invalidEventName", // eventName is empty, has more than 50 values or invalid characters
INVALID_EVENT_TYPE = "invalidEventType", // eventType is not "INFO", "WARNING" or "ERROR"
INVALID_OUTPUT_FORMAT = "invalidOutputFormat", // outputFormat is not "json" or "csv"
}
{
"errorMessage": "Page size must be an integer between 1 and 5000",
"errorType": "invalidPageSize"
}
Search timeout
Describe the characteristics of a search that took too long
504
Response body
{
"errorMessage": "The search took too long. Try a smaller time range or page size.",
"errorType": "searchQueryTimeout"
}
Description: the page could not be resolved in time. Retry the same request (with the same cursor) or split the search into shorter time ranges.
Internal error
Describe the characteristics of an internal error
500
Response body
{
"message": "Internal server error"
}
Description: the search failed. No partial results are returned: retry the same request.