List security events
US Region: https://public-api.sessionboard.com · EU Region: https://public-api-eu.sessionboard.com
Sign-ins, sign-in failures, two-factor and passkey events, password resets and session changes for the people in your organization. Covers events recorded against the organization and those of its current members. Sessionboard staff activity is not included. No retention limit.
Request example
curl --request GET \ --url 'https://public-api.sessionboard.com/v1/logs/security-events' \ --header 'x-access-token: <api-token>'const response = await fetch('https://public-api.sessionboard.com/v1/logs/security-events', { method: 'GET', headers: { "x-access-token": "<api-token>" },});
const data = await response.json();console.log(data);import requests
response = requests.request( "GET", "https://public-api.sessionboard.com/v1/logs/security-events", headers={ "x-access-token": "<api-token>" },)
print(response.json())<?php
$curl = curl_init();
curl_setopt_array($curl, [ CURLOPT_URL => "https://public-api.sessionboard.com/v1/logs/security-events", CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => [ "x-access-token: <api-token>", ],]);
$response = curl_exec($curl);curl_close($curl);
echo $response;package main
import ( "fmt" "io" "net/http")
func main() { req, _ := http.NewRequest("GET", "https://public-api.sessionboard.com/v1/logs/security-events", nil) req.Header.Add("x-access-token", "<api-token>")
res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))}HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://public-api.sessionboard.com/v1/logs/security-events")) .header("x-access-token", "<api-token>") .method("GET", HttpRequest.BodyPublishers.noBody()) .build();
HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());Try it
Response headers
Authorizations
x-access-tokenstringheaderrequiredOrganization API token. Generate from Organization Settings → API Tokens.
Query parameters
cursorstringquerynext_cursorfrom the previous page. Store it after each page and send it back unchanged; it remembers your filters, so repeat the same filters with it.- Max length
2048
sincestring<date-time>queryWhere to start when you have no cursor. Defaults to 24 hours ago. Ignored when
cursoris sent.limitintegerqueryEvents per page.
- Default
500- Minimum
1- Maximum
1000
outcomestringqueryOnly successful or only failed events.
- Allowed values
"success", "failure"
Responses
200application/json
One page of events, oldest first.
dataLogEvent[]requiredShow child attributes
idstringStable event id. Use it to de-duplicate if you replay a page.
streamstringWhich log the event came from —
api_requestfrom/v1/logs/api-requests,security_eventfrom/v1/logs/security-events,auditfrom/v1/logs/audit-trail.- Allowed values
"api_request", "security_event", "audit"
occurred_atstring<date-time>When the event happened.
ingested_atstring<date-time>When Sessionboard recorded it. Pages are ordered by this.
actionstringGET /v1/eventsfor API requests, the event type (for examplelogin.password_okorlogin.challenge_failed) for security events,<subject_type>.<operation>for the audit trail.- Example
"GET /v1/events"
outcomestring- Allowed values
"success", "failure", "unknown"
reasonstring | nullWhy it failed, when it did.
actorobjectShow child attributes
typestringapi_token,oauth_tokenoranonymousfor API requests;useroradminfor security events;user,systemorrule(an automation) for the audit trail.idstring | nullnamestring | nulltoken_hintstring | nullLast characters of the token id, for API requests.
user_emailstring | null
src_ipstring | nulluser_agentstring | nullstatusinteger | nullHTTP status, for API requests.
duration_msinteger | nullResponse time, for API requests.
targetobject | nullShow child attributes
typestring- Example
"event"
idstring
detailsobjectStream-specific fields (for example
sourceandrequest_idfor API requests,propertyandvaluefor the audit trail).
next_cursorstringrequiredSend this as
cursoron the next call. On an empty page it is the cursor you sent, so a caught-up poller keeps it and waits.has_morebooleanrequiredtruewhen more events are ready now — fetch again immediately.falsemeans wait before polling.
RateLimit-LimitintegerheaderRequests allowed in the current window.
RateLimit-RemainingintegerheaderRequests left in the current window.
400application/json
VALIDATION_ERROR for a bad parameter; INVALID_CURSOR for a cursor that is malformed or was issued for another stream or organization;
CURSOR_FILTER_MISMATCH when the filters differ from the ones the cursor was issued with;
SINCE_BEFORE_RETENTION when since is older than the stream keeps.
errorstring- Allowed values
"VALIDATION_ERROR", "INVALID_CURSOR", "CURSOR_FILTER_MISMATCH", "SINCE_BEFORE_RETENTION", "CURSOR_EXPIRED"
messagestring
401
Missing, invalid, revoked or expired API token.
403
The token does not hold read:audit_logs, or it is an OAuth token. Log export accepts API tokens only.
410application/json
CURSOR_EXPIRED — the cursor points before the start of retention. Restart from since.
errorstring- Allowed values
"VALIDATION_ERROR", "INVALID_CURSOR", "CURSOR_FILTER_MISMATCH", "SINCE_BEFORE_RETENTION", "CURSOR_EXPIRED"
messagestring
429
Rate limited. 60 requests per minute per token; honor Retry-After.
Response examples
{ "data": [ { "id": "<string>", "stream": "api_request", "occurred_at": "2026-01-15T09:30:00Z", "ingested_at": "2026-01-15T09:30:00Z", "action": "GET /v1/events", "outcome": "success", "reason": "<string>", "actor": { "type": "<string>", "id": "<string>", "name": "<string>", "token_hint": "<string>", "user_email": "<string>" }, "src_ip": "<string>", "user_agent": "<string>", "status": 123, "duration_ms": 123, "target": { "type": "event", "id": "<string>" }, "details": {} } ], "next_cursor": "<string>", "has_more": true}{ "error": "VALIDATION_ERROR", "message": "<string>"}{ "error": "VALIDATION_ERROR", "message": "<string>"}