curl --request POST \
--url https://api.cloud.corbado.io/v1/observe/events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sessionID": "550e8400-e29b-41d4-a716-446655440000",
"events": [
{
"name": "flow_started",
"timestamp": 1752738240000,
"id": "550e8400-e29b-41d4-a716-446655440000",
"data": {},
"meta": {
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"subflowStartEventId": "<string>",
"trackingSourcePath": "<string>",
"tabId": "<string>"
},
"user": {
"userId": "<string>",
"identifier": "<string>",
"crossEnvironmentTransactionIDStart": "<string>",
"crossEnvironmentTransactionIDFinish": "<string>",
"crossEnvironmentTransactionID": "<string>"
},
"tags": {},
"experiments": {},
"seq": 123
}
],
"deliveryAck": true,
"lows": [
{
"lowType": "<string>",
"ts": 123,
"captureSeq": 2147483647,
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"id": "<string>",
"subflowStartEventId": "<string>",
"sourceKind": "<string>",
"fieldRole": "<string>",
"inputEffect": "<string>",
"durationMs": 123,
"fieldType": "<string>",
"actor": "<string>"
}
],
"telemetry": [
{
"message": "<string>",
"ts": 123,
"id": "<string>"
}
]
}
'import requests
url = "https://api.cloud.corbado.io/v1/observe/events"
payload = {
"sessionID": "550e8400-e29b-41d4-a716-446655440000",
"events": [
{
"name": "flow_started",
"timestamp": 1752738240000,
"id": "550e8400-e29b-41d4-a716-446655440000",
"data": {},
"meta": {
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"subflowStartEventId": "<string>",
"trackingSourcePath": "<string>",
"tabId": "<string>"
},
"user": {
"userId": "<string>",
"identifier": "<string>",
"crossEnvironmentTransactionIDStart": "<string>",
"crossEnvironmentTransactionIDFinish": "<string>",
"crossEnvironmentTransactionID": "<string>"
},
"tags": {},
"experiments": {},
"seq": 123
}
],
"deliveryAck": True,
"lows": [
{
"lowType": "<string>",
"ts": 123,
"captureSeq": 2147483647,
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"id": "<string>",
"subflowStartEventId": "<string>",
"sourceKind": "<string>",
"fieldRole": "<string>",
"inputEffect": "<string>",
"durationMs": 123,
"fieldType": "<string>",
"actor": "<string>"
}
],
"telemetry": [
{
"message": "<string>",
"ts": 123,
"id": "<string>"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sessionID: '550e8400-e29b-41d4-a716-446655440000',
events: [
{
name: 'flow_started',
timestamp: 1752738240000,
id: '550e8400-e29b-41d4-a716-446655440000',
data: {},
meta: {
captureVersion: 123,
pageId: '<string>',
initiator: '<string>',
subflowStartEventId: '<string>',
trackingSourcePath: '<string>',
tabId: '<string>'
},
user: {
userId: '<string>',
identifier: '<string>',
crossEnvironmentTransactionIDStart: '<string>',
crossEnvironmentTransactionIDFinish: '<string>',
crossEnvironmentTransactionID: '<string>'
},
tags: {},
experiments: {},
seq: 123
}
],
deliveryAck: true,
lows: [
{
lowType: '<string>',
ts: 123,
captureSeq: 2147483647,
captureVersion: 123,
pageId: '<string>',
initiator: '<string>',
id: '<string>',
subflowStartEventId: '<string>',
sourceKind: '<string>',
fieldRole: '<string>',
inputEffect: '<string>',
durationMs: 123,
fieldType: '<string>',
actor: '<string>'
}
],
telemetry: [{message: '<string>', ts: 123, id: '<string>'}]
})
};
fetch('https://api.cloud.corbado.io/v1/observe/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloud.corbado.io/v1/observe/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionID' => '550e8400-e29b-41d4-a716-446655440000',
'events' => [
[
'name' => 'flow_started',
'timestamp' => 1752738240000,
'id' => '550e8400-e29b-41d4-a716-446655440000',
'data' => [
],
'meta' => [
'captureVersion' => 123,
'pageId' => '<string>',
'initiator' => '<string>',
'subflowStartEventId' => '<string>',
'trackingSourcePath' => '<string>',
'tabId' => '<string>'
],
'user' => [
'userId' => '<string>',
'identifier' => '<string>',
'crossEnvironmentTransactionIDStart' => '<string>',
'crossEnvironmentTransactionIDFinish' => '<string>',
'crossEnvironmentTransactionID' => '<string>'
],
'tags' => [
],
'experiments' => [
],
'seq' => 123
]
],
'deliveryAck' => true,
'lows' => [
[
'lowType' => '<string>',
'ts' => 123,
'captureSeq' => 2147483647,
'captureVersion' => 123,
'pageId' => '<string>',
'initiator' => '<string>',
'id' => '<string>',
'subflowStartEventId' => '<string>',
'sourceKind' => '<string>',
'fieldRole' => '<string>',
'inputEffect' => '<string>',
'durationMs' => 123,
'fieldType' => '<string>',
'actor' => '<string>'
]
],
'telemetry' => [
[
'message' => '<string>',
'ts' => 123,
'id' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloud.corbado.io/v1/observe/events"
payload := strings.NewReader("{\n \"sessionID\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"events\": [\n {\n \"name\": \"flow_started\",\n \"timestamp\": 1752738240000,\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"data\": {},\n \"meta\": {\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"trackingSourcePath\": \"<string>\",\n \"tabId\": \"<string>\"\n },\n \"user\": {\n \"userId\": \"<string>\",\n \"identifier\": \"<string>\",\n \"crossEnvironmentTransactionIDStart\": \"<string>\",\n \"crossEnvironmentTransactionIDFinish\": \"<string>\",\n \"crossEnvironmentTransactionID\": \"<string>\"\n },\n \"tags\": {},\n \"experiments\": {},\n \"seq\": 123\n }\n ],\n \"deliveryAck\": true,\n \"lows\": [\n {\n \"lowType\": \"<string>\",\n \"ts\": 123,\n \"captureSeq\": 2147483647,\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"id\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"sourceKind\": \"<string>\",\n \"fieldRole\": \"<string>\",\n \"inputEffect\": \"<string>\",\n \"durationMs\": 123,\n \"fieldType\": \"<string>\",\n \"actor\": \"<string>\"\n }\n ],\n \"telemetry\": [\n {\n \"message\": \"<string>\",\n \"ts\": 123,\n \"id\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloud.corbado.io/v1/observe/events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sessionID\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"events\": [\n {\n \"name\": \"flow_started\",\n \"timestamp\": 1752738240000,\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"data\": {},\n \"meta\": {\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"trackingSourcePath\": \"<string>\",\n \"tabId\": \"<string>\"\n },\n \"user\": {\n \"userId\": \"<string>\",\n \"identifier\": \"<string>\",\n \"crossEnvironmentTransactionIDStart\": \"<string>\",\n \"crossEnvironmentTransactionIDFinish\": \"<string>\",\n \"crossEnvironmentTransactionID\": \"<string>\"\n },\n \"tags\": {},\n \"experiments\": {},\n \"seq\": 123\n }\n ],\n \"deliveryAck\": true,\n \"lows\": [\n {\n \"lowType\": \"<string>\",\n \"ts\": 123,\n \"captureSeq\": 2147483647,\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"id\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"sourceKind\": \"<string>\",\n \"fieldRole\": \"<string>\",\n \"inputEffect\": \"<string>\",\n \"durationMs\": 123,\n \"fieldType\": \"<string>\",\n \"actor\": \"<string>\"\n }\n ],\n \"telemetry\": [\n {\n \"message\": \"<string>\",\n \"ts\": 123,\n \"id\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloud.corbado.io/v1/observe/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionID\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"events\": [\n {\n \"name\": \"flow_started\",\n \"timestamp\": 1752738240000,\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"data\": {},\n \"meta\": {\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"trackingSourcePath\": \"<string>\",\n \"tabId\": \"<string>\"\n },\n \"user\": {\n \"userId\": \"<string>\",\n \"identifier\": \"<string>\",\n \"crossEnvironmentTransactionIDStart\": \"<string>\",\n \"crossEnvironmentTransactionIDFinish\": \"<string>\",\n \"crossEnvironmentTransactionID\": \"<string>\"\n },\n \"tags\": {},\n \"experiments\": {},\n \"seq\": 123\n }\n ],\n \"deliveryAck\": true,\n \"lows\": [\n {\n \"lowType\": \"<string>\",\n \"ts\": 123,\n \"captureSeq\": 2147483647,\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"id\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"sourceKind\": \"<string>\",\n \"fieldRole\": \"<string>\",\n \"inputEffect\": \"<string>\",\n \"durationMs\": 123,\n \"fieldType\": \"<string>\",\n \"actor\": \"<string>\"\n }\n ],\n \"telemetry\": [\n {\n \"message\": \"<string>\",\n \"ts\": 123,\n \"id\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"version": "3f2a1b9c0d4e",
"flushIntervalMs": 500,
"durableLowOutbox": true,
"durableOutbox": true,
"beaconKeepalive": true,
"sessionContinuity": true,
"sessionInactivityMs": 1800000,
"seqLockTimeoutMs": 5,
"tvc": true,
"tph": true,
"td": true,
"rawErrors": true,
"telemetry": true,
"flushOnTelemetry": true,
"flushOnEventNames": [
"flow_finished",
"conversion"
],
"flushOnFlowTypeFinished": [
"login",
"enrollment"
],
"deviceInfoCollectorTimeoutMs": 1000,
"deviceInfoTiming": true,
"aap": "c1",
"sourcePathQuery": "allowlist",
"sourcePathQueryAllow": [
"utm_*",
"section"
],
"retry": {
"maxAttempts": 5,
"baseDelayMs": 500,
"maxDelayMs": 15000
}
}{
"error": {
"message": "Validation failed",
"details": [
{
"field": "projectID",
"message": "required"
}
]
}
}Create new events
Ingests events from your backend using an API key. For browser and native collection, use the Observe SDKs and their separate project-scoped transport.
Server-side enrichment
Attach a user reference or tags, such as a risk or bot verdict, to a flow without sending them through the browser. Target a flow by event ID or temporal matching; authenticated enrichment allows a symmetric 10-second matching tolerance.
A request accepts at most 2,000 events and low-level events combined.
Required API key permission: observe:events:write.
curl --request POST \
--url https://api.cloud.corbado.io/v1/observe/events \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sessionID": "550e8400-e29b-41d4-a716-446655440000",
"events": [
{
"name": "flow_started",
"timestamp": 1752738240000,
"id": "550e8400-e29b-41d4-a716-446655440000",
"data": {},
"meta": {
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"subflowStartEventId": "<string>",
"trackingSourcePath": "<string>",
"tabId": "<string>"
},
"user": {
"userId": "<string>",
"identifier": "<string>",
"crossEnvironmentTransactionIDStart": "<string>",
"crossEnvironmentTransactionIDFinish": "<string>",
"crossEnvironmentTransactionID": "<string>"
},
"tags": {},
"experiments": {},
"seq": 123
}
],
"deliveryAck": true,
"lows": [
{
"lowType": "<string>",
"ts": 123,
"captureSeq": 2147483647,
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"id": "<string>",
"subflowStartEventId": "<string>",
"sourceKind": "<string>",
"fieldRole": "<string>",
"inputEffect": "<string>",
"durationMs": 123,
"fieldType": "<string>",
"actor": "<string>"
}
],
"telemetry": [
{
"message": "<string>",
"ts": 123,
"id": "<string>"
}
]
}
'import requests
url = "https://api.cloud.corbado.io/v1/observe/events"
payload = {
"sessionID": "550e8400-e29b-41d4-a716-446655440000",
"events": [
{
"name": "flow_started",
"timestamp": 1752738240000,
"id": "550e8400-e29b-41d4-a716-446655440000",
"data": {},
"meta": {
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"subflowStartEventId": "<string>",
"trackingSourcePath": "<string>",
"tabId": "<string>"
},
"user": {
"userId": "<string>",
"identifier": "<string>",
"crossEnvironmentTransactionIDStart": "<string>",
"crossEnvironmentTransactionIDFinish": "<string>",
"crossEnvironmentTransactionID": "<string>"
},
"tags": {},
"experiments": {},
"seq": 123
}
],
"deliveryAck": True,
"lows": [
{
"lowType": "<string>",
"ts": 123,
"captureSeq": 2147483647,
"captureVersion": 123,
"pageId": "<string>",
"initiator": "<string>",
"id": "<string>",
"subflowStartEventId": "<string>",
"sourceKind": "<string>",
"fieldRole": "<string>",
"inputEffect": "<string>",
"durationMs": 123,
"fieldType": "<string>",
"actor": "<string>"
}
],
"telemetry": [
{
"message": "<string>",
"ts": 123,
"id": "<string>"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sessionID: '550e8400-e29b-41d4-a716-446655440000',
events: [
{
name: 'flow_started',
timestamp: 1752738240000,
id: '550e8400-e29b-41d4-a716-446655440000',
data: {},
meta: {
captureVersion: 123,
pageId: '<string>',
initiator: '<string>',
subflowStartEventId: '<string>',
trackingSourcePath: '<string>',
tabId: '<string>'
},
user: {
userId: '<string>',
identifier: '<string>',
crossEnvironmentTransactionIDStart: '<string>',
crossEnvironmentTransactionIDFinish: '<string>',
crossEnvironmentTransactionID: '<string>'
},
tags: {},
experiments: {},
seq: 123
}
],
deliveryAck: true,
lows: [
{
lowType: '<string>',
ts: 123,
captureSeq: 2147483647,
captureVersion: 123,
pageId: '<string>',
initiator: '<string>',
id: '<string>',
subflowStartEventId: '<string>',
sourceKind: '<string>',
fieldRole: '<string>',
inputEffect: '<string>',
durationMs: 123,
fieldType: '<string>',
actor: '<string>'
}
],
telemetry: [{message: '<string>', ts: 123, id: '<string>'}]
})
};
fetch('https://api.cloud.corbado.io/v1/observe/events', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.cloud.corbado.io/v1/observe/events",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionID' => '550e8400-e29b-41d4-a716-446655440000',
'events' => [
[
'name' => 'flow_started',
'timestamp' => 1752738240000,
'id' => '550e8400-e29b-41d4-a716-446655440000',
'data' => [
],
'meta' => [
'captureVersion' => 123,
'pageId' => '<string>',
'initiator' => '<string>',
'subflowStartEventId' => '<string>',
'trackingSourcePath' => '<string>',
'tabId' => '<string>'
],
'user' => [
'userId' => '<string>',
'identifier' => '<string>',
'crossEnvironmentTransactionIDStart' => '<string>',
'crossEnvironmentTransactionIDFinish' => '<string>',
'crossEnvironmentTransactionID' => '<string>'
],
'tags' => [
],
'experiments' => [
],
'seq' => 123
]
],
'deliveryAck' => true,
'lows' => [
[
'lowType' => '<string>',
'ts' => 123,
'captureSeq' => 2147483647,
'captureVersion' => 123,
'pageId' => '<string>',
'initiator' => '<string>',
'id' => '<string>',
'subflowStartEventId' => '<string>',
'sourceKind' => '<string>',
'fieldRole' => '<string>',
'inputEffect' => '<string>',
'durationMs' => 123,
'fieldType' => '<string>',
'actor' => '<string>'
]
],
'telemetry' => [
[
'message' => '<string>',
'ts' => 123,
'id' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.cloud.corbado.io/v1/observe/events"
payload := strings.NewReader("{\n \"sessionID\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"events\": [\n {\n \"name\": \"flow_started\",\n \"timestamp\": 1752738240000,\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"data\": {},\n \"meta\": {\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"trackingSourcePath\": \"<string>\",\n \"tabId\": \"<string>\"\n },\n \"user\": {\n \"userId\": \"<string>\",\n \"identifier\": \"<string>\",\n \"crossEnvironmentTransactionIDStart\": \"<string>\",\n \"crossEnvironmentTransactionIDFinish\": \"<string>\",\n \"crossEnvironmentTransactionID\": \"<string>\"\n },\n \"tags\": {},\n \"experiments\": {},\n \"seq\": 123\n }\n ],\n \"deliveryAck\": true,\n \"lows\": [\n {\n \"lowType\": \"<string>\",\n \"ts\": 123,\n \"captureSeq\": 2147483647,\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"id\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"sourceKind\": \"<string>\",\n \"fieldRole\": \"<string>\",\n \"inputEffect\": \"<string>\",\n \"durationMs\": 123,\n \"fieldType\": \"<string>\",\n \"actor\": \"<string>\"\n }\n ],\n \"telemetry\": [\n {\n \"message\": \"<string>\",\n \"ts\": 123,\n \"id\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.cloud.corbado.io/v1/observe/events")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sessionID\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"events\": [\n {\n \"name\": \"flow_started\",\n \"timestamp\": 1752738240000,\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"data\": {},\n \"meta\": {\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"trackingSourcePath\": \"<string>\",\n \"tabId\": \"<string>\"\n },\n \"user\": {\n \"userId\": \"<string>\",\n \"identifier\": \"<string>\",\n \"crossEnvironmentTransactionIDStart\": \"<string>\",\n \"crossEnvironmentTransactionIDFinish\": \"<string>\",\n \"crossEnvironmentTransactionID\": \"<string>\"\n },\n \"tags\": {},\n \"experiments\": {},\n \"seq\": 123\n }\n ],\n \"deliveryAck\": true,\n \"lows\": [\n {\n \"lowType\": \"<string>\",\n \"ts\": 123,\n \"captureSeq\": 2147483647,\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"id\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"sourceKind\": \"<string>\",\n \"fieldRole\": \"<string>\",\n \"inputEffect\": \"<string>\",\n \"durationMs\": 123,\n \"fieldType\": \"<string>\",\n \"actor\": \"<string>\"\n }\n ],\n \"telemetry\": [\n {\n \"message\": \"<string>\",\n \"ts\": 123,\n \"id\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloud.corbado.io/v1/observe/events")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionID\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"events\": [\n {\n \"name\": \"flow_started\",\n \"timestamp\": 1752738240000,\n \"id\": \"550e8400-e29b-41d4-a716-446655440000\",\n \"data\": {},\n \"meta\": {\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"trackingSourcePath\": \"<string>\",\n \"tabId\": \"<string>\"\n },\n \"user\": {\n \"userId\": \"<string>\",\n \"identifier\": \"<string>\",\n \"crossEnvironmentTransactionIDStart\": \"<string>\",\n \"crossEnvironmentTransactionIDFinish\": \"<string>\",\n \"crossEnvironmentTransactionID\": \"<string>\"\n },\n \"tags\": {},\n \"experiments\": {},\n \"seq\": 123\n }\n ],\n \"deliveryAck\": true,\n \"lows\": [\n {\n \"lowType\": \"<string>\",\n \"ts\": 123,\n \"captureSeq\": 2147483647,\n \"captureVersion\": 123,\n \"pageId\": \"<string>\",\n \"initiator\": \"<string>\",\n \"id\": \"<string>\",\n \"subflowStartEventId\": \"<string>\",\n \"sourceKind\": \"<string>\",\n \"fieldRole\": \"<string>\",\n \"inputEffect\": \"<string>\",\n \"durationMs\": 123,\n \"fieldType\": \"<string>\",\n \"actor\": \"<string>\"\n }\n ],\n \"telemetry\": [\n {\n \"message\": \"<string>\",\n \"ts\": 123,\n \"id\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"version": "3f2a1b9c0d4e",
"flushIntervalMs": 500,
"durableLowOutbox": true,
"durableOutbox": true,
"beaconKeepalive": true,
"sessionContinuity": true,
"sessionInactivityMs": 1800000,
"seqLockTimeoutMs": 5,
"tvc": true,
"tph": true,
"td": true,
"rawErrors": true,
"telemetry": true,
"flushOnTelemetry": true,
"flushOnEventNames": [
"flow_finished",
"conversion"
],
"flushOnFlowTypeFinished": [
"login",
"enrollment"
],
"deviceInfoCollectorTimeoutMs": 1000,
"deviceInfoTiming": true,
"aap": "c1",
"sourcePathQuery": "allowlist",
"sourcePathQueryAllow": [
"utm_*",
"section"
],
"retry": {
"maxAttempts": 5,
"baseDelayMs": 500,
"maxDelayMs": 15000
}
}{
"error": {
"message": "Validation failed",
"details": [
{
"field": "projectID",
"message": "required"
}
]
}
}Authorizations
Use an Observe API key from the management console. The key selects the project and must grant the permission listed on the operation. Keep this key on your server.
Body
Session ID for the events (UUID format)
"550e8400-e29b-41d4-a716-446655440000"
Array of events to create. The combined number of events and lows must be at least 1 and at most 2000.
Show child attributes
Show child attributes
Request synchronous durable ingestion. Only a committed request returns X-Corbado-Observe-Accepted=1; temporary persistence failures return 503. Legacy delivery is unchanged.
Array of low-level events to create. The combined number of events and lows must be at least 1 and at most 2000.
Show child attributes
Show child attributes
Diagnostic telemetry entries (SDK/integration-side messages, not auth-flow events). They ride along with the normal event batch, are tied to the same session, and never participate in flow classification. A batch may carry telemetry only (no events/lows). Capped at 2000 per batch.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Identity of the SDK that produced the batch. Clients have always sent this; it is declared here so the backend can branch on it (e.g. serve the app-specific reliability config to native SDKs). Optional for backwards compatibility.
Show child attributes
Show child attributes
Response
SDK reliability configuration (returned only when the X-Corbado-Observe-Config header is set). The shape depends on the requesting SDK: web SDKs receive observeEventCreateRes, native app SDKs (request sdk.name observe-android/observe-ios) receive the app-specific observeSdkConfigApp.
- Option 1
- Option 2
SDK reliability configuration. Returned from the event ingestion endpoints only when the client opts in
by sending the X-Corbado-Observe-Config request header carrying the config version the client is
currently running (or 1 when it has none cached). When the sent version matches the current one the
endpoints return 204 No Content (nothing new); without the header they always return 204, so this is
a fully backwards-compatible addition. The SDK applies a received config on its next page load
(boot-snapshot model) and stamps the version it ran under into each batch's meta.configVersion.
Content-derived version (hash) of this configuration. Changes whenever any value changes. The SDK
caches it, echoes it in the X-Corbado-Observe-Config request header, and stamps it into
meta.configVersion of every event batch so analyses can segment by the config actually in effect.
"3f2a1b9c0d4e"
How often the SDK should flush its event queue, in milliseconds.
500
Persist lows in a separate bounded outbox and require durable server acknowledgement. Default false.
Whether the SDK should persist queued events to a durable outbox so they survive reloads, redirects and browser-context switches.
Whether the SDK should use keepalive/sendBeacon transport for flushes triggered during page unload.
Whether the SDK should maintain session continuity across browser-context switches (e.g. in-app browser to system browser).
Inactivity threshold for continuity sessions, in milliseconds. When more time than this has
passed since the last tracked activity, the SDK rotates to a new session id on the next load.
Only relevant when sessionContinuity is enabled.
1800000
Maximum time to wait for the cross-tab sequence Web Lock before allocating without it, in milliseconds. Clamped to 0–100ms. 0 is a sentinel that disables the lock: the SDK then allocates the sequence counter without requesting a lock at all, giving up cross-tab atomicity (two tabs can allocate the same seq) to save a lock round-trip per event.
5
Flush-trigger switch: flush pending events when the document becomes hidden (visibilitychange).
Default true; the SDK treats a missing value as true, so delivery can never be disabled by accident.
Flush-trigger switch: flush pending events on pagehide (navigation/close). Default true.
Flush-trigger switch: flush pending events when the integrator calls destroy(). Default true.
Enables serialization of explicitly supplied raw error diagnostics into stepData.rawError. Server default is true; an explicit false disables diagnostics. Normalized errors are always reported independently. SDK built-in defaults may differ (Android defaults off). SDKs apply this using their normal config lifecycle; disabling affects newly captured diagnostics, not events already queued.
Master switch for the diagnostic telemetry stream. When true the SDK sends buffered telemetry
entries (observeTelemetry) piggybacked on normal event requests; when false it collects nothing
and sends nothing. Lets telemetry be turned off server-side without a customer redeploy.
When true (and telemetry is enabled), enqueuing a telemetry entry triggers an immediate client
flush so diagnostics go out promptly (e.g. before a crash/navigation). Default false: a telemetry
entry alone never triggers a flush, it only rides the next flush caused by anything else.
Superseded by flushOnFlowTypeFinished; served only for SDK versions that predate it (they
ignore the new field, newer SDKs ignore this one). Event names that trigger an immediate
client-side flush when enqueued (e.g. flow_finished, conversion), so high-value events go
out while the page is still alive instead of relying on unload delivery. Empty = no priority
events. Capped at 20 names (both sides).
["flow_finished", "conversion"]
Flow types whose completion triggers an immediate client-side flush when enqueued, so the
highest-value events go out while the page is still alive instead of relying on unload
delivery. Both completion events count — flow_finished and flow_auto_finished — matched
on their flowName; no other event name ever flushes early. Empty = no priority flows.
Capped at 20 entries (both sides). Replaces flushOnEventNames, which SDKs from the version
that introduced this field on no longer read.
["login", "enrollment"]
Per-field timeout for the SDK's device info collection, in milliseconds. A browser API that does not answer within this budget is recorded as a timeout in the event's device info collection errors and the field stays empty; the other fields are unaffected. Clamped to 10–10000ms. The SDK reads it per collection run, so a new value takes effect from the next device info refresh; the first collection of a load without a cached config runs on the built-in default.
1000
When true (and telemetry is enabled), every device info collection emits an info telemetry
entry carrying the total duration and each field's duration in milliseconds. Default false —
a diagnostic stream to switch on while investigating slow collection, not for permanent use.
Durations of fields that hit deviceInfoCollectorTimeoutMs are censored at that value.
Capability policy token for Corbado frontend SDKs and adapters. Values are assigned by Corbado per project and select how a capability behaves for that project; an SDK that does not implement the token it receives ignores it and keeps its standard behavior. Empty (the default) always means standard behavior. Capped at 16 characters — a longer value is served as empty.
"c1"
Which query values the SDK includes in the page URL it reports as meta.trackingSourcePath:
allowlist (the default) or all. allowlist keeps every query key and its position but
replaces each value with * unless its key is listed in sourcePathQueryAllow (empty by
default, so every value is masked); empty values and keys without a value stay as they are.
all sends the query unchanged. The path itself is never changed. Any value other than all
(including unset or empty) is served as allowlist. Server-side email/phone redaction still
applies to whatever is sent.
"allowlist"
Query keys whose values are kept when sourcePathQuery is allowlist. Matched
case-insensitively and exactly; a trailing * matches a key prefix (utm_*). Empty or
oversized entries (more than 64 characters) are dropped and the list is capped at 50 entries
(both sides). Empty by default. Ignored in all mode.
["utm_*", "section"]
Client-side retry configuration (exponential backoff) for failed event flushes.
Show child attributes
Show child attributes
Was this page helpful?