curl -X POST 'https://verification.didit.me/v3/events/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"event_id": "login-2026-10-17-000001",
"event_category": "auth",
"action_type": "login",
"occurred_at": "2026-10-17T09:15:02.481Z",
"subject": {"vendor_data": "user-42", "entity_type": "individual"},
"session": {"session_id": "web-session-abc", "sequence": 142},
"device_context": {
"fingerprint": "fp-a8c1",
"network_context": {"ip_address": "203.0.113.42"}
},
"payload": {"method": "password"}
}'import os
import requests
resp = requests.post(
'https://verification.didit.me/v3/events/',
headers={'x-api-key': os.environ['DIDIT_API_KEY']},
json={
'event_id': 'login-2026-10-17-000001',
'event_category': 'auth',
'action_type': 'login',
'occurred_at': '2026-10-17T09:15:02.481Z',
'subject': {'vendor_data': 'user-42', 'entity_type': 'individual'},
'session': {'session_id': 'web-session-abc', 'sequence': 142},
'device_context': {
'fingerprint': 'fp-a8c1',
'network_context': {'ip_address': '203.0.113.42'},
},
'payload': {'method': 'password'},
},
timeout=10,
)
resp.raise_for_status()
result = resp.json()
print(result['event_uuid'], result['status'], result['idempotent_replay'])const resp = await fetch('https://verification.didit.me/v3/events/', {
method: 'POST',
headers: {
'x-api-key': process.env.DIDIT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_id: 'login-2026-10-17-000001',
event_category: 'auth',
action_type: 'login',
occurred_at: '2026-10-17T09:15:02.481Z',
subject: { vendor_data: 'user-42', entity_type: 'individual' },
session: { session_id: 'web-session-abc', sequence: 142 },
device_context: {
fingerprint: 'fp-a8c1',
network_context: { ip_address: '203.0.113.42' },
},
payload: { method: 'password' },
}),
});
if (!resp.ok) throw new Error(await resp.text());
const result = await resp.json();
console.log(result.event_uuid, result.status, result.idempotent_replay);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/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([
'event_id' => 'login-2026-10-17-000001',
'event_category' => 'auth',
'action_type' => 'login',
'occurred_at' => '2026-10-17T09:15:02.481Z',
'time_zone' => 'Europe/Madrid',
'subject' => [
'vendor_data' => 'user-42',
'entity_type' => 'individual'
],
'session' => [
'session_id' => 'web-session-abc',
'sequence' => 142
],
'device_context' => [
'fingerprint' => 'fp-a8c1',
'network_context' => [
'ip_address' => '203.0.113.42'
]
],
'payload' => [
'method' => 'password'
],
'custom_values' => [
'vip_tier' => 'gold'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$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://verification.didit.me/v3/events/"
payload := strings.NewReader("{\n \"event_id\": \"login-2026-10-17-000001\",\n \"event_category\": \"auth\",\n \"action_type\": \"login\",\n \"occurred_at\": \"2026-10-17T09:15:02.481Z\",\n \"time_zone\": \"Europe/Madrid\",\n \"subject\": {\n \"vendor_data\": \"user-42\",\n \"entity_type\": \"individual\"\n },\n \"session\": {\n \"session_id\": \"web-session-abc\",\n \"sequence\": 142\n },\n \"device_context\": {\n \"fingerprint\": \"fp-a8c1\",\n \"network_context\": {\n \"ip_address\": \"203.0.113.42\"\n }\n },\n \"payload\": {\n \"method\": \"password\"\n },\n \"custom_values\": {\n \"vip_tier\": \"gold\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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://verification.didit.me/v3/events/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"event_id\": \"login-2026-10-17-000001\",\n \"event_category\": \"auth\",\n \"action_type\": \"login\",\n \"occurred_at\": \"2026-10-17T09:15:02.481Z\",\n \"time_zone\": \"Europe/Madrid\",\n \"subject\": {\n \"vendor_data\": \"user-42\",\n \"entity_type\": \"individual\"\n },\n \"session\": {\n \"session_id\": \"web-session-abc\",\n \"sequence\": 142\n },\n \"device_context\": {\n \"fingerprint\": \"fp-a8c1\",\n \"network_context\": {\n \"ip_address\": \"203.0.113.42\"\n }\n },\n \"payload\": {\n \"method\": \"password\"\n },\n \"custom_values\": {\n \"vip_tier\": \"gold\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/events/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"event_id\": \"login-2026-10-17-000001\",\n \"event_category\": \"auth\",\n \"action_type\": \"login\",\n \"occurred_at\": \"2026-10-17T09:15:02.481Z\",\n \"time_zone\": \"Europe/Madrid\",\n \"subject\": {\n \"vendor_data\": \"user-42\",\n \"entity_type\": \"individual\"\n },\n \"session\": {\n \"session_id\": \"web-session-abc\",\n \"sequence\": 142\n },\n \"device_context\": {\n \"fingerprint\": \"fp-a8c1\",\n \"network_context\": {\n \"ip_address\": \"203.0.113.42\"\n }\n },\n \"payload\": {\n \"method\": \"password\"\n },\n \"custom_values\": {\n \"vip_tier\": \"gold\"\n }\n}"
response = http.request(request)
puts response.read_body{
"event_uuid": "33333333-4444-5555-6666-777777777777",
"event_id": "login-2026-10-17-000001",
"status": "ACCEPTED",
"score": 0,
"rules_evaluated_count": 6,
"rules_matched_count": 0,
"correlation_pending": false,
"retention_class": "standard",
"expires_at": "2026-11-16T09:15:02.481000Z",
"idempotent_replay": true,
"rule_matches": []
}Create Monitoring Event
Send one login, gameplay, bonus, payment, dispute or security event from your backend to be stored, enriched and scored by your event rules.
curl -X POST 'https://verification.didit.me/v3/events/' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"event_id": "login-2026-10-17-000001",
"event_category": "auth",
"action_type": "login",
"occurred_at": "2026-10-17T09:15:02.481Z",
"subject": {"vendor_data": "user-42", "entity_type": "individual"},
"session": {"session_id": "web-session-abc", "sequence": 142},
"device_context": {
"fingerprint": "fp-a8c1",
"network_context": {"ip_address": "203.0.113.42"}
},
"payload": {"method": "password"}
}'import os
import requests
resp = requests.post(
'https://verification.didit.me/v3/events/',
headers={'x-api-key': os.environ['DIDIT_API_KEY']},
json={
'event_id': 'login-2026-10-17-000001',
'event_category': 'auth',
'action_type': 'login',
'occurred_at': '2026-10-17T09:15:02.481Z',
'subject': {'vendor_data': 'user-42', 'entity_type': 'individual'},
'session': {'session_id': 'web-session-abc', 'sequence': 142},
'device_context': {
'fingerprint': 'fp-a8c1',
'network_context': {'ip_address': '203.0.113.42'},
},
'payload': {'method': 'password'},
},
timeout=10,
)
resp.raise_for_status()
result = resp.json()
print(result['event_uuid'], result['status'], result['idempotent_replay'])const resp = await fetch('https://verification.didit.me/v3/events/', {
method: 'POST',
headers: {
'x-api-key': process.env.DIDIT_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_id: 'login-2026-10-17-000001',
event_category: 'auth',
action_type: 'login',
occurred_at: '2026-10-17T09:15:02.481Z',
subject: { vendor_data: 'user-42', entity_type: 'individual' },
session: { session_id: 'web-session-abc', sequence: 142 },
device_context: {
fingerprint: 'fp-a8c1',
network_context: { ip_address: '203.0.113.42' },
},
payload: { method: 'password' },
}),
});
if (!resp.ok) throw new Error(await resp.text());
const result = await resp.json();
console.log(result.event_uuid, result.status, result.idempotent_replay);<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://verification.didit.me/v3/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([
'event_id' => 'login-2026-10-17-000001',
'event_category' => 'auth',
'action_type' => 'login',
'occurred_at' => '2026-10-17T09:15:02.481Z',
'time_zone' => 'Europe/Madrid',
'subject' => [
'vendor_data' => 'user-42',
'entity_type' => 'individual'
],
'session' => [
'session_id' => 'web-session-abc',
'sequence' => 142
],
'device_context' => [
'fingerprint' => 'fp-a8c1',
'network_context' => [
'ip_address' => '203.0.113.42'
]
],
'payload' => [
'method' => 'password'
],
'custom_values' => [
'vip_tier' => 'gold'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$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://verification.didit.me/v3/events/"
payload := strings.NewReader("{\n \"event_id\": \"login-2026-10-17-000001\",\n \"event_category\": \"auth\",\n \"action_type\": \"login\",\n \"occurred_at\": \"2026-10-17T09:15:02.481Z\",\n \"time_zone\": \"Europe/Madrid\",\n \"subject\": {\n \"vendor_data\": \"user-42\",\n \"entity_type\": \"individual\"\n },\n \"session\": {\n \"session_id\": \"web-session-abc\",\n \"sequence\": 142\n },\n \"device_context\": {\n \"fingerprint\": \"fp-a8c1\",\n \"network_context\": {\n \"ip_address\": \"203.0.113.42\"\n }\n },\n \"payload\": {\n \"method\": \"password\"\n },\n \"custom_values\": {\n \"vip_tier\": \"gold\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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://verification.didit.me/v3/events/")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"event_id\": \"login-2026-10-17-000001\",\n \"event_category\": \"auth\",\n \"action_type\": \"login\",\n \"occurred_at\": \"2026-10-17T09:15:02.481Z\",\n \"time_zone\": \"Europe/Madrid\",\n \"subject\": {\n \"vendor_data\": \"user-42\",\n \"entity_type\": \"individual\"\n },\n \"session\": {\n \"session_id\": \"web-session-abc\",\n \"sequence\": 142\n },\n \"device_context\": {\n \"fingerprint\": \"fp-a8c1\",\n \"network_context\": {\n \"ip_address\": \"203.0.113.42\"\n }\n },\n \"payload\": {\n \"method\": \"password\"\n },\n \"custom_values\": {\n \"vip_tier\": \"gold\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://verification.didit.me/v3/events/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"event_id\": \"login-2026-10-17-000001\",\n \"event_category\": \"auth\",\n \"action_type\": \"login\",\n \"occurred_at\": \"2026-10-17T09:15:02.481Z\",\n \"time_zone\": \"Europe/Madrid\",\n \"subject\": {\n \"vendor_data\": \"user-42\",\n \"entity_type\": \"individual\"\n },\n \"session\": {\n \"session_id\": \"web-session-abc\",\n \"sequence\": 142\n },\n \"device_context\": {\n \"fingerprint\": \"fp-a8c1\",\n \"network_context\": {\n \"ip_address\": \"203.0.113.42\"\n }\n },\n \"payload\": {\n \"method\": \"password\"\n },\n \"custom_values\": {\n \"vip_tier\": \"gold\"\n }\n}"
response = http.request(request)
puts response.read_body{
"event_uuid": "33333333-4444-5555-6666-777777777777",
"event_id": "login-2026-10-17-000001",
"status": "ACCEPTED",
"score": 0,
"rules_evaluated_count": 6,
"rules_matched_count": 0,
"correlation_pending": false,
"retention_class": "standard",
"expires_at": "2026-11-16T09:15:02.481000Z",
"idempotent_replay": true,
"rule_matches": []
}403 with "code": "event_monitoring_disabled".Authorizations
Your application's API key, from Developers -> API keys in the Business Console. The primary key has full access. A named key can be scoped: none, read or write per resource, limited to some workflows or to approved sessions, to a list of IP addresses, and to an expiry date. 401 means the key is missing, wrong, revoked or expired; 403 means the key has no access to this resource or action, or the request came from an address outside its IP list; 404 on a session route means the session is outside the key's workflows or statuses. A key without media access receives image, video and PDF URLs as null, and a key without sessions write receives session links and tokens as null. See https://docs.didit.me/console/api-keys.
Body
The event envelope, the same for every category. camelCase aliases are accepted: eventId, eventCategory (or category), actionType, occurredAt, timeZone (or zoneId), deviceContext (or device), transactionContext, customValues (or props); inside subject: vendorData, entityType, fullName; inside session: sessionId, pageUrl; inside transaction_context: paymentReferenceId.
Your identifier for the event, unique per application. It is the idempotency key: resending the same event_category, action_type, occurred_at, subject.vendor_data and payload under it is a replay, anything different is a conflict.
128"login-2026-10-17-000001"
Event category.
auth, session, gameplay, bonus, affiliate, payment, dispute, security, responsible_gambling, custom "auth"
What happened within the category. Open vocabulary; the managed actions listed in Event ingestion (for example login, deposit_completed, chargeback_opened) unlock typed validation and managed rule fields. Leading and trailing whitespace is trimmed.
1 - 128"login"
When the event happened on your side, ISO 8601 (a value without an offset is read as UTC). Must be no more than 7 days in the past and no more than 5 minutes in the future.
"2026-10-17T09:15:02.481Z"
The user or company the event belongs to. It resolves to the user (or company) with this vendor_data in your application; one is created when none exists.
Show child attributes
Show child attributes
Time zone of the occurrence on your side, for example Europe/Madrid. Stored with the event; not returned by the read endpoints.
64The business the event belongs to, when it differs from the subject. Only vendor_data is read.
Show child attributes
Show child attributes
Your session context for the event.
Show child attributes
Show child attributes
Device and network context, stored as sent and returned by GET /v3/events/{event_uuid}/. On this server lane Didit does not see the end user's connection, so the IP enriched and used by rules is network_context.ip_address as you send it.
Show child attributes
Show child attributes
Money context. Non-empty values here also satisfy the required payload keys of the action.
Show child attributes
Show child attributes
The category's domain fields, at most 16384 bytes once JSON-encoded. Some actions require keys (in payload or transaction_context): gameplay.p2p_settlement needs game_id, counterparty_vendor_data, stake_amount, net_result_amount, role and one of hand_id, round_id, match_id; gameplay.bet_placed and gameplay.bet_settled need game_id; payment.deposit_initiated, payment.deposit_completed, payment.withdrawal_requested and payment.withdrawal_completed need payment_reference_id, amount, currency, payment_method, status; payment.withdrawal_address_changed needs withdrawal_address_hash; dispute.chargeback_opened, dispute.chargeback_won and dispute.chargeback_lost need payment_reference_id and one of dispute_id, chargeback_id; session.bot_signal_observed needs telemetry_schema_version and one of bot_score, actions_per_minute, timing_variance_ms, pointer_entropy, keystroke_entropy, reaction_time_ms_p50; responsible_gambling.self_exclusion_match needs registry_source, exclusion_status, identity_match_ref. Every security action ending in _changed needs changed_field, plus previous_reference_hash or new_reference_hash when the field is password, mfa_method, mfa, email, phone, withdrawal_address, payout_method or api_key. Send hashes and references, never a card number, a full withdrawal address, a password hash or an MFA secret.
Up to 100 keys of your own, addressable from rules as custom_values.<key>. Values must be scalars (string, number, boolean or null); nested objects and arrays are rejected.
Show child attributes
Show child attributes
Response
Idempotent replay: an event with this event_id and the same content is already stored. Nothing was stored or evaluated again; the body describes the stored event.
Outcome of ingesting one event. The same shape is returned for a new event and for an idempotent replay.
Didit identifier of the stored event.
Your event_id.
Status after the real-time rules ran. See MonitoringEvent.status.
ACCEPTED, APPROVED, IN_REVIEW, DECLINED Score after the real-time rules ran.
Number of event rules evaluated in the request. 0 in a sandbox application, where no rules run.
x >= 0Number of rules that matched, including TEST mode rules.
x >= 0true when an asynchronous rule still has to run. Read GET /v3/events/{event_uuid}/ a few minutes later for the final status and score.
Retention class, after any promotion by a matched rule.
low_value, standard, risk_relevant, monetary_or_compliance When the event expires under its retention class and is deleted. Null for monetary_or_compliance (payment and dispute) events.
true when an event with this event_id and the same content was already stored; the values are those of the stored event and no rule ran again.
Rules that matched the event.
Show child attributes
Show child attributes