Events
Ingest events from SDKs and server-side integrations using sdk.events.v1.EventsService/BatchCreate.
Auth: x-api-key header (public key pub_… or private key prv_…). No Authorization header or x-project-id is required — the project is resolved from the key. See Authentication.
BatchCreate
POST /sdk.events.v1.EventsService/BatchCreateValidates and enqueues up to 1 000 events in a single request. Returns the count of accepted events. There is no single-event endpoint — all ingestion goes through this method.
All google.protobuf.Timestamp fields (here, occurTime, and timestampValue inside a PropertyValue) serialize as RFC 3339 strings — e.g. "2026-06-05T10:00:00Z".
Event fields
| Proto field | JSON name | Type | Required | Notes |
|---|---|---|---|---|
event_id | eventId | string | Yes | UUID (any version; UUIDv7 recommended for time-sortability) |
auto_properties | autoProperties | map<string, PropertyValue> | No | Context set by the SDK or server. Keys must start with $. $bot_score and $verified_bot are server-only — any client-supplied value is stripped and replaced from CDN headers |
custom_properties | customProperties | map<string, PropertyValue> | No | Your event properties. Keys must not start with $ |
distinct_id | distinctId | string | Yes | Anonymous or identified user ID |
kind | kind | string | Yes | Event name. Must not start with pug. (reserved prefix) |
occur_time | occurTime | google.protobuf.Timestamp → RFC 3339 | Yes | When the event occurred |
session_id | sessionId | string | Yes | UUID grouping events in a visit |
Proto field names (snake_case) and lowerCamelCase are both accepted by the Connect JSON codec. The lowerCamelCase forms shown above are canonical.
PropertyValue — typed property wrapper
Every value in customProperties and autoProperties is a wrapped object that names its type explicitly. This is the Connect JSON encoding of the protobuf oneof.
| Variant | JSON shape | Notes |
|---|---|---|
| String | { "stringValue": "hello" } | Max 1 024 Unicode code points. Values exceeding the limit are rejected with invalid_argument (not truncated) |
| Integer | { "intValue": "42" } | int64 — the value is a JSON string, not a number |
| Double | { "doubleValue": 3.14 } | Must be finite (NaN and ±Infinity are rejected) |
| Boolean | { "boolValue": true } | |
| Timestamp | { "timestampValue": "2026-06-05T10:00:00Z" } | RFC 3339; stored at millisecond precision |
Exactly one variant must be set per PropertyValue object. Proto snake_case aliases (e.g. string_value) are accepted as well.
Validation summary
All rules above enforced together; any violation fails the request with invalid_argument:
- Batch size — at most 1 000 events per
BatchCreatecall. eventId,sessionId— must be valid UUIDs.$bot_score,$verified_bot— server-only; any client-supplied value is dropped and re-set from the CDN-injectedCF-Bot-Score/CF-Verified-Botheaders.
(Property-key prefix rules, stringValue length, and doubleValue finiteness are covered in the Event fields and PropertyValue tables above.)
Request / response shape
Property values are typed
PropertyValuewrappers. Every value incustomPropertiesandautoPropertiesnames its type explicitly —intValue(int64) must be a JSON string, doubles are bare numbers, etc. (see the table above). This is not how profile traits work: Identify’straitsare plain JSON, notPropertyValue-wrapped — see Profiles.
BatchCreateRequest
{
"events": [
{
"eventId": "<uuid>",
"distinctId": "anon-abc123",
"kind": "page_view",
"sessionId": "<uuid>",
"occurTime": "2026-06-05T10:00:00Z",
"customProperties": {
"plan": { "stringValue": "pro" },
"seats": { "intValue": "5" },
"mrr": { "doubleValue": 299.0 },
"trial": { "boolValue": false }
},
"autoProperties": {}
}
]
}BatchCreateResponse
{ "accepted": 1 }accepted (uint32) is the number of events that passed validation and were enqueued. It equals the number of events in the request when all events are valid.
Errors
These are the codes BatchCreate returns in practice — a subset of the full
error model:
| Connect code | HTTP status | Cause |
|---|---|---|
unauthenticated | 401 | Missing or invalid x-api-key |
invalid_argument | 400 | Validation failed — see the message field for which rule |
resource_exhausted | 429 | Rate limit exceeded |
internal | 500 | Server error — retry with exponential backoff |
Error responses follow the Connect envelope:
{
"code": "invalid_argument",
"message": "event kind must not use reserved prefix 'pug.'"
}Further reading
- HTTP transport — full curl, Python, and Go examples for
BatchCreate - Auto-properties — the
$-prefixed property catalog set by the server - Authentication — public vs. private keys, key rotation